This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Add key argument to collections.Counter
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.11
process
Status: closed Resolution: duplicate
Dependencies: Superseder:
Assigned To: Nosy List: Dennis Sweeney, kubataytekin, rhettinger
Priority: normal Keywords:

Created on 2021-10-01 08:19 by kubataytekin, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (5)
msg403002 - (view) Author: kubat aytekin (kubataytekin) Date: 2021-10-01 08:19
Counter has become the default tool for counting occurences of objects in an iterable. However by construction it only works on hashable objects as it is a subclass of dict. Would it be possible to implement a "key=" keyword argument as in sort etc.? 

Here's a stackoverflow question wherein either map or implementing a hash method was proposed:
https://stackoverflow.com/questions/69401713/elegant-way-of-counting-items-in-a-list-by-enum-value-in-python
msg403027 - (view) Author: Dennis Sweeney (Dennis Sweeney) * (Python committer) Date: 2021-10-01 19:24
How is Counter(numbers, key=abs) any better than Counter(map(abs, numbers))?

It seems to me that "apply a function to each thing" (map) and "count the numbers of each thing" (Counter) are two orthogonal concepts, and there's no reason to entangle them. Their composition as "count the number of things with each function value" is probably better as a composition of two simple things rather than lumped together. I believe this is related to why PEP 455 was rejected.
msg403030 - (view) Author: kubat aytekin (kubataytekin) Date: 2021-10-01 20:18
I was thinking about use cases where one might want to preserve the original key. I was not however aware of PEP 455 and the reasons for it's rejection. My bad.

Yet It is still unclear to me what the best practice would be to reverse lookup unhashable objects. Say you have a list of objects from which you need the most common. If there is no good way of reversing the transform, your only option is iterating trough your list? Which defeats the purpose of using a Counter and you'd be better off counting explicitly. Maybe I'm imagining unrealistic/far-fetched use cases.
msg403031 - (view) Author: Dennis Sweeney (Dennis Sweeney) * (Python committer) Date: 2021-10-01 20:26
The values of a Counter are generally integers, not lists. Maybe you want:

    items_by_keyfunc = defaultdict(list)
    for x in all_the_items:
        items_by_keyfunc[keyfunc(x)].append(x)

Then items_by_keyfunc[42] is a list of the things with key 42.

Although I believe there have been proposals about adding some method to dict() to do basically the for-loop above.
msg403033 - (view) Author: kubat aytekin (kubataytekin) Date: 2021-10-01 20:41
Or keep the reverse mapping in another dict:
    
    count = Counter()
    reverse_mapping = dict()
    for x in all_the_items:
        count.update(keyfunc(x))
        reverse_mapping[keyfunc(x)] = x

Anyways I'm closing it as it is a partial duplicate of key-transforming dictionaries.
History
Date User Action Args
2022-04-11 14:59:50adminsetgithub: 89501
2021-10-01 20:41:50kubataytekinsetstatus: open -> closed
resolution: duplicate
messages: + msg403033

stage: resolved
2021-10-01 20:26:02Dennis Sweeneysetmessages: + msg403031
2021-10-01 20:18:49kubataytekinsetmessages: + msg403030
2021-10-01 19:33:40xtreaksetnosy: + rhettinger
2021-10-01 19:24:18Dennis Sweeneysetnosy: + Dennis Sweeney
messages: + msg403027
2021-10-01 08:19:49kubataytekincreate