Unordered list as dict key

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.