在 Python 字典中按值查找键的有效方法,其中字典值是可迭代的
Efficient way to find key by value in Python dict where dict values are iterables
我有一个可迭代的唯一数字:
lst = [14, 11, 8, 55]
其中每个值都在 dict 的可迭代值中的某个位置,比如列表:
dict_itms.items() = dict_items([(1, [0, 1, 2, 3]), (2, [11, 14, 12]), (3, [30, 8, 42]), (4, [55, 6])])
我必须在 dict 中找到每个 lst
元素,这样,最后,我将得到一个针对 lst 中每个元素的成对键列表。
这个方法:
keys_ = []
for a in lst:
for k, v in dict_itms.items():
if a in v:
keys_ += [k]
break
else:
continue
给出:
[2, 2, 3, 4]
是否有更有效的方法来找到每对要查找的每个数字的每个键?
您可以在列表理解中使用 any
:
print([k for k,v in dict_itms.items() if any(x in lst for x in v)])
输出:
[2, 3, 4]
更新
据此 answer not set(v).isdisjoint(lst)
是最快的:
print([k for k,v in dict_itms.items() if not set(v).isdisjoint(lst)])
一个简单的 Pythonic 实现:
d = dict([(1, [0, 1, 2, 3]), (2, [11, 14, 12]), (3, [30, 8, 42]), (4, [55, 6])])
xs = [14, 11, 8, 55]
keys = [k for k, v in d.items() if set(v).intersection(xs)]
print(keys)
但是,这不会复制 2 键,而您的示例确实如此 - 不确定这是否是您需要的行为?
不清楚你所说的 'efficient' 是什么意思;你需要它在 given pass 或 aggregate 中有效吗?我问的原因是,通常最好的总体处理方式是通过预处理来翻转键值关系:
reverse_lookup = dict()
for k,v in d.items():
for i in v:
keys = reverse_lookup.get(i, []) # Provide an empty list if this item not yet found
keys.append(k)
reverse_lookup[i] = keys
现在您已经处理了反向查找,您可以直接使用它:
result = [reverse_lookup.get(i) for i in lst]
# `result` is actually a list of lists, so as to allow duplicates. You will need to flatten it, or change the reverse lookup to ignore dupes.
反向查找的初始处理是O(n*m)
,其中n*m
是原始字典值求和的总长度。但是,lst
部分的每次查找都是 O(1)
,所以如果你眯着眼睛进行足够的查找,这是 O(p)
,其中 p
是 lst
的长度.如果你必须做很多,这将比其他方法更有效,如果你只传递一次给定的字典,效率会低得多。
我有一个可迭代的唯一数字:
lst = [14, 11, 8, 55]
其中每个值都在 dict 的可迭代值中的某个位置,比如列表:
dict_itms.items() = dict_items([(1, [0, 1, 2, 3]), (2, [11, 14, 12]), (3, [30, 8, 42]), (4, [55, 6])])
我必须在 dict 中找到每个 lst
元素,这样,最后,我将得到一个针对 lst 中每个元素的成对键列表。
这个方法:
keys_ = []
for a in lst:
for k, v in dict_itms.items():
if a in v:
keys_ += [k]
break
else:
continue
给出:
[2, 2, 3, 4]
是否有更有效的方法来找到每对要查找的每个数字的每个键?
您可以在列表理解中使用 any
:
print([k for k,v in dict_itms.items() if any(x in lst for x in v)])
输出:
[2, 3, 4]
更新
据此 answer not set(v).isdisjoint(lst)
是最快的:
print([k for k,v in dict_itms.items() if not set(v).isdisjoint(lst)])
一个简单的 Pythonic 实现:
d = dict([(1, [0, 1, 2, 3]), (2, [11, 14, 12]), (3, [30, 8, 42]), (4, [55, 6])])
xs = [14, 11, 8, 55]
keys = [k for k, v in d.items() if set(v).intersection(xs)]
print(keys)
但是,这不会复制 2 键,而您的示例确实如此 - 不确定这是否是您需要的行为?
不清楚你所说的 'efficient' 是什么意思;你需要它在 given pass 或 aggregate 中有效吗?我问的原因是,通常最好的总体处理方式是通过预处理来翻转键值关系:
reverse_lookup = dict()
for k,v in d.items():
for i in v:
keys = reverse_lookup.get(i, []) # Provide an empty list if this item not yet found
keys.append(k)
reverse_lookup[i] = keys
现在您已经处理了反向查找,您可以直接使用它:
result = [reverse_lookup.get(i) for i in lst]
# `result` is actually a list of lists, so as to allow duplicates. You will need to flatten it, or change the reverse lookup to ignore dupes.
反向查找的初始处理是O(n*m)
,其中n*m
是原始字典值求和的总长度。但是,lst
部分的每次查找都是 O(1)
,所以如果你眯着眼睛进行足够的查找,这是 O(p)
,其中 p
是 lst
的长度.如果你必须做很多,这将比其他方法更有效,如果你只传递一次给定的字典,效率会低得多。