【问题标题】:2d dictionary with many keys that will return the same value具有许多将返回相同值的键的二维字典
【发布时间】:2012-10-31 11:27:43
【问题描述】:

我想制作一个每个值有多个键的二维字典。我不想使元组成为键。而是创建许多返回相同值的键。

我知道如何使用 defaultdict 制作二维字典:

from collections import defaultdict
a_dict = defaultdict(dict)

a_dict['canned_food']['spam'] = 'delicious'

我可以使用一个元组作为键

a_dict['food','canned_food']['spam'] = 'delicious'

但这不允许我做类似的事情

print a_dict['canned_food']['spam']

因为 'canned_food' 不是键,所以元组 ['food','canned_food'] 是键。

我了解到我可以简单地将许多独立设置为相同的值,例如:

a_dict['food']['spam'] = 'delicious'
a_dict['canned_food']['spam'] = 'delicious'

但这会因为大量的键而变得混乱。在字典的第一维中,每个值我需要约 25 个键。有没有办法编写字典,以便元组中的任何键都可以工作?

I have asked this question before 但不清楚我想要什么,所以我重新发布。提前感谢您的帮助。

【问题讨论】:

  • 从技术上讲,您将元组设为键,而不是列表。
  • 有点不清楚您希望它如何运作。一个值可以在多个键中吗?
  • 是的,一个值会有多个键。
  • 对不起,我不清楚我的意思,我的意思是如果你有键的元组(它们都指同一个项目),这些元组可能有相同的“子键”吗?例如:('food', 'canned_food')('canned_food', 'canned_beans') 都是键。如果是这样,他们应该如何表现?
  • 我想我明白你在说什么。字典第一维中的键总是不同于字典第二维中的键。它是层次结构。如果它是一个类别并且也在某个子类别中,我想为它分配一个值。我的问题是我有很多类别都具有相同的子类别。

标签: python dictionary python-2.x


【解决方案1】:

这是一个可能的解决方案:

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()]))

可以这样使用:

>>> 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'})])

请注意,有些极端情况的行为未定义 - 例如对多个别名使用相同的键。我觉得这使得这种数据类型对于一般用途来说非常糟糕,我建议你最好改变你的程序而不需要这种过于复杂的结构。

另请注意,此解决方案适用于 3.x,在 2.x 下,您需要将 str 替换为 basestring,将 self.aliases.keys() 替换为 self.aliases.viewkeys()

【讨论】:

  • 谢谢你,这似乎工作得很好。我确实必须在第 13 行将 &amp; 更改为 and 才能正常工作。不过我不是很明白,我得仔细看代码,我刚开始接触python。
  • &amp;and 是不同的,在这里并不等同。问题可能是您使用的是 2.x,而我使用的是 3.x - 在这种情况下,诀窍是使用 self.aliases.viewkeys() 来使其正常工作。我在那里做的是设置交集,而 2.x 从keys() 返回的列表不像设置,所以它会失败。
  • 对不起我的无知。所以我将self.aliases.keys(): 更改为self.aliases.viewkeys(): 但我有一个错误: Traceback(最近一次调用最后一次):文件“/Users/keithfritzsching/Text-3.py”,第 30 行,在 a_dict = AliasDefaultDict() TypeError: __init__() 正好接受 2 个参数(1 个给定)
  • collections.defaultdict一样,需要传递默认值函数。在你的情况下,dict。抱歉,我没有更新我的示例。
  • 非常感谢您的解决方案。我需要做一些工作才能理解它,但你非常有帮助!
【解决方案2】:

这有帮助吗?

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

输出是

{'a': 10, 'c': 20, 'b': 20}

【讨论】:

  • 这不起作用,因为提问者没有分配给键,他分配给键下的字典。另外,为什么要直接迭代 key.__iter__() 而不是 key,以及为什么随便的 except: - 捕获所有异常总是一个坏主意。
  • 是的,它很老套,但如果它是明智的,建议更好地实施。但是,是的,点接受,这不是正确的答案。如果你使用简洁的表示,一个困难是你最终可能会得到重复的键
  • 其实我认为当值是另一个字典时它解决了问题
猜你喜欢
  • 1970-01-01
  • 2022-01-18
  • 2014-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 2021-05-09
相关资源
最近更新 更多