2d dictionary with many keys that will return the same value

风流意气都作罢 提交于 2019-12-03 22:14:06

Here is a possible solution:

from collections import Iterable

class AliasDefaultDict():
    def __init__(self, default_factory, initial=[]):
        self.aliases = {}
        self.data = {}
        self.factory = default_factory
        for aliases, value in initial:
            self[aliases] = value

    @staticmethod
    def distinguish_keys(key):
        if isinstance(key, Iterable) and not isinstance(key, str):
            return set(key)
        else:
            return {key}

    def __getitem__(self, key):
        keys = self.distinguish_keys(key)
        if keys & self.aliases.keys():
            return self.data[self.aliases[keys.pop()]]
        else:
            value = self.factory()
            self[keys] = value
            return value

    def __setitem__(self, key, value):
        keys = self.distinguish_keys(key)
        if keys & self.aliases.keys():
            self.data[self.aliases[keys.pop()]] = value
        else:
            new_key = object()
            self.data[new_key] = value
            for key in keys:
                self.aliases[key] = new_key
            return value

    def __repr__(self):
        representation = defaultdict(list)
        for alias, value in self.aliases.items():
            representation[value].append(alias)
        return "AliasDefaultDict({}, {})".format(repr(self.factory), repr([(aliases, self.data[value]) for value, aliases in representation.items()]))

Which can be used like so:

>>> a_dict = AliasDefaultDict(dict)
>>> a_dict['food', 'canned_food']['spam'] = 'delicious'
>>> a_dict['food']
{'spam': 'delicious'}
>>> a_dict['canned_food']
{'spam': 'delicious'}
>> a_dict
AliasDefaultDict(<class 'dict'>, [(['food', 'canned_food'], {'spam': 'delicious'})])

Note there are some edge cases with undefined behavior - such as using the same key for multiple aliases. I feel this makes this data type pretty awful for general use, and I'd suggest that you may be better off changing your program not to need this kind of overly convoluted structure instead.

Also note this solution is for 3.x, under 2.x, you will want to swap out str for basestring, and self.aliases.keys() for self.aliases.viewkeys().

Does this help at all?

class MultiDict(dict):
    # define __setitem__ to set multiple keys if the key is iterable
    def __setitem__(self, key, value):
        try:
            # attempt to iterate though items in the key
            for val in key:
                dict.__setitem__(self, val, value)
        except:
            # not iterable (or some other error, but just a demo)
            # just set that key
            dict.__setitem__(self, key, value)



x = MultiDict()

x["a"]=10
x["b","c"] = 20

print x

The output is

{'a': 10, 'c': 20, 'b': 20}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!