检查给定的键是否包含在多个字典中。

5
我有多个字典,其中包含根据业务价值而定的数据,例如:
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}
...

我需要检查变量x是否包含在这些字典中的任何一个中,并确定它包含在哪个字典中。可能有大量这样的字典,因此手动检查不是很有效。有没有比手动检查更符合Python风格的方法?

if x in companies:
    pass    # do something
elif x in names:
    pass    # do something
...

在列表中循环并在找到关键字时停止。或者一次性处理/合并字典,生成值的列表。 - Jean-François Fabre
7个回答

4

编码简单/快速:在字典列表中循环,找到后停止。

但如果要执行多个搜索,则复杂性不好处理。相反,创建一个字典的字典。

  • 键是键的并集
  • 值是由(值,原始字典)组成的元组列表

就像这样:

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

import collections

c = collections.defaultdict(list)

for d in [companies,names]:
    for k,v in d.items():
        c[k].append((v,d))

现在:

print(c.get('google'))

输出:

[('value_1', {'google': 'value_1', 'facebook': 'value_2'})

现在,如果我在这两个字典中添加一个共同的键:
names = {'alex': 'value_3', 'john': 'value_4', 'facebook':'value_5'}
print(c.get('facebook'))

我们得到一个包含所有值和原始字典的列表:

[('value_2', {'google': 'value_1', 'facebook': 'value_2'}),
 ('value_5', {'alex': 'value_3', 'john': 'value_4', 'facebook': 'value_5'})]

通过这种解决方案,即使你有很多字典,一旦建立了新的大字典,查找速度也总是O(1)。在2或3次查找之后,构建会被摊销。

如上所述,我们看到原始字典已被保留。现在您可以选择如何标识此字典。我选择将参考本身作为我没有约束条件。


3

不要为每个 x 每次循环遍历所有的字典,你可以构建一个包含该键的字典名称作为值的所有键的字典。

这样一来,您将仅对所有字典进行一次循环以构建您的“查找表”,然后对“x”的每次访问都不再需要任何循环。

例如:

my_dicts = {'companies': {'google': 'value_1', 'facebook': 'value_2', 'alex': 'yo'},
            'names': {'alex': 'value_3', 'john': 'value_4'}}

# build the lookup dict
lookup = {}
for dk, dv in my_dicts.items():
    for k in dv.keys():
        dl = lookup.get(k, [])
        lookup[k] = dl + [dk]

现在,您可以直接访问具有您的x键的字典:
x = 'alex'
dict_names = lookup[x]

for dn in dict_names:
    # do something on my_dict[dn]
    print(dn)

公司名称


3
你可以使用这些字典来创建一个列表:
dictionaries = [companies, names]

for dictionary in dictionaries:
        if keyword in dictionary:

3
我会使用一个 list 来存储所有的字典,然后只需使用列表推导式过滤掉不包含您键的字典:
companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

x = 'john'

dicts = [companies, names]

contains_key = [d for d in dicts if x in d]

对于大量词典,比如数千个,这种方法不如@Jean-François Fabre的答案具有可扩展性,但这是一种简单的方法。


2

实现方法:

  • 使用filter函数查找包含搜索关键字的字典
  • 使用next()函数迭代一次以获取第一个匹配项(实际上是获取任何匹配项)
  • 使用default参数避免StopIteration异常(你也可以返回字典:next(..., {})
def find_dict(x, *dicts):
    return next(filter(lambda d: x in d, dicts), None)

使用:

if __name__ == '__main__':
    companies = {'google': 'value_1', 'facebook': 'value_2'}
    names = {'alex': 'value_3', 'john': 'value_4'}
    x = 'alex'

    print(find_dict(x, companies, names)) # {'alex': 'value_3', 'john': 'value_4'}
    print(find_dict('foo', companies, names)) # None

2
一个简单的方法是将字典放在列表中,迭代每个字典,并检查 x 是否存在于每个字典中:
from json import dumps

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

lst = [companies, names]

x = 'google'

for dic in lst:
    if x in dic:
        print('%s exists in dict %s' %(key, dumps(dic)))

# google exists in dict {"google": "value_1", "facebook": "value_2"}

但是这种方法很慢,因为您需要迭代列表中的每个字典进行查找。每次查找的时间复杂度将为O(D),其中D是列表中字典的数量。
更快的方法是使用defaultdict(list)来收集每个键的字典,然后后续的查找时间复杂度为O(1)。但是构建此字典将是一个O(D * K)的操作(D =字典数,K =每个字典的键数),因为我们需要迭代每个字典及其键。如果您要进行大量查找,则长期来看进行此转换将是值得的。
from collections import defaultdict
from json import dumps

companies = {'google': 'value_1', 'facebook': 'value_2'}
names = {'alex': 'value_3', 'john': 'value_4'}

lst = [companies, names]

x = 'google'

all_dicts = defaultdict(list)
for dic in lst:
    for key in dic:
        all_dicts[key].append(dic)

print("%s exists in these dictionaries : %s" % (x, dumps(all_dicts[x])))
# google exists in these dictionaries : [{"google": "value_1", "facebook": "value_2"}]

1
Python字典中的keyview对象实际上类似于集合。您可以轻松地将它们转换为集合:
>>> a = {'a':1, 'b':2}
>>> b = {'a':2, 'c':3}
>>> a.keys() | b.keys()
{'a', 'b', 'c'}

现在你需要做的就是检查集合中的成员资格。
>>> if x in that_set: ...

如果您有大量的字典,您可以查看此答案以了解如何合并多个集合,但请记住set.union(dict.keys())是不合法的...
>>> set.union(a.keys())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor 'union' for 'set' objects doesn't apply to a 'dict_keys' object

所以你需要做类似这样的事情。
>>> all_keys = set.union(*(set(d) for d in all_dicts))

在推导式中,可以将每个字典显式转换为集合。

当然,你也可以将所有字典合并,达到类似的效果:

>>> all_dicts = {**dict1, **dict2, **dict3}
>>> "key" in all_dicts

这仍然是一种非常有效的方法,可以找到所有字典中给定键的至少一个值,尽管它仍然不能告诉您该键在哪个字典中。为了解决这个问题,恐怕您必须进行迭代。azro's fine answer 告诉您如何做到这一点。

你的回答如何解决这个问题,即如何确定它包含在哪个字典中? - Jean-François Fabre
混合键后很难找到正确的字典。 - azro
谢谢,我已经更新了我的答案,提供了两个替代方案--我认为除了暴力破解之外,无法识别原始字典,但也有可能OP或任何未来的读者只想获取任何一个字典中匹配键的值。我也提供了解决方案。 - kojiro
最后一种方法也不能处理字典之间的重复键。 - RoadRunner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接