I want to be able to do something like:
foo = Counter(['bar', 'shoo', 'bar'])
tmp = {}
tmp[foo] = 5
In other words, is there a hashable equivalent for Counter
?
Note that I can't use frozenset
since I have repeated elements that I want to keep in the key.
Edit: In my actual application, the objects in foo may not be comparable with each other so the list cannot be sorted.
A dictionary or a list cannot be a key. Values, on the other hand, can literally be anything and they can be used more than once.
We can use integer, string, tuples as dictionary keys but cannot use list as a key of it .
You cannot use a list as a key because a list is mutable. Similarly, you cannot use a tuple as a key if any of its elements are lists. (You can only use a tuple as a key if all of its elements are immutable.)
The dict. keys() method in Python Dictionary, returns a view object that displays a list of all the keys in the dictionary in order of insertion.
What you seem to require is a way to use unordered pairs of key-amount as keys. A frozenset
is probably the way to go, although you will have to create it out of the items
of the Counter
and not its keys
.
foo = Counter(['bar', 'shoo', 'bar'])
tmp = {}
tmp[frozenset(foo.items())] = 5
# tmp: {frozenset({('bar', 2), ('shoo', 1)}): 5}
If this is satisfying, you could implement this transformation by defining you own mapping type like so:
from collections import Counter
class CounterDict:
def __init__(self):
self.data = {}
def __setitem__(self, key, value):
if isinstance(key, Counter):
self.data[frozenset(key.items())] = value
else:
raise TypeError
def __getitem__(self, key):
if isinstance(key, Counter):
return self.data[frozenset(key.items())]
else:
raise TypeError
foo = Counter(['bar', 'shoo', 'bar'])
tmp = CounterDict()
tmp[foo] = 42
tmp[foo] # 42
You could make this implementation richer by making CounterDict
a subclass of collections.UserDict
.
There are a couple of things you could do. One is to sort the list and convert the result to a tuple
. That will work fine for small lists.
If you have large lists (with duplicates), you could convert it into a frozenset
whose elements are tuples which are (word, count) pairs. So for the example, if your list is ['bar', 'shoo', 'bar']
, you would have frozenset({('bar', 2), ('shoo', 1)})
.
You could construct this by using Counter
, or else just construct a dict
of word: count
entries, then convert the entries to tuples and construct a frozenset
from them.
Both of these would be hashable, and support duplicate elements in the original list.
Using the string representation of the Counter?
foo = Counter(['bar', 'shoo', 'bar'])
tmp = {}
tmp[str(foo)] = 5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With