Why doesn't collections.Counter support a "key" argument in its constructor?

Peter Otten __peter__ at web.de
Sat Sep 12 13:00:39 EDT 2020


Saurav Chirania wrote:

> I really like that python's sort method accepts a key function as a
> parameter which can be used to specify how elements should be compared.
> 
> Similarly, we could have a "key" argument which specifies how elements
> should be counted. Let's say we have a list of a million students. I would
> like to do something like:
> c = Counter(students, key = lambda student: student.marks)
> 
> which would return a Counter which maps marks to the number of students
> with that marks. Let's say 29 students in the list had scored 100 marks,
> so one entry in the counter would be key=100, val=29.
> 
> So, why doesn't Counter's constructor support this argument? Are there
> other pythonic ways to do this?

Yes, as the counter won't store the original student there is no advantage 
over the direct translation of your code

Counter(map(lambda: student.marks, students))

or the more elegant variant with a generator expression

Counter(student.marks for student in students)

Functions like max() which do offer a key arg are a bit different as

max(student.marks for student in students)

returns the highest marks whereas

max(students, key=lambda: student.marks)

returns the student with the highest marks. To spell the latter without a 
key arg would require something more complicated like

max((s.marks, i, s) for i, s in enumerate(students))[-1]

If you need to count the marks while remembering the students you would use 
a dict or defaultdict instead of a counter,

d = defaultdict(list)
for s in students:
    d[s.marks] = s

or, if the students are sorted by marks, itertools.groupby().



More information about the Python-list mailing list