如何在defaultdict中有效地进行反向查找?

时间:2017-06-13 22:06:27

标签: python performance python-3.x defaultdict

我在发布这个问题之前做了一些搜索,似乎有几种不同的方法来实现这一点。

但是目前(使用Python 3)根据defaultdict中的特定值搜索关键字的最有效方法是什么,它看起来像这样:

defaultdict(list,
            {'a': [[2, 3], [1, 2]],
             'b': [[5, 6]],
             'w': [[]],
             'x': [[9]],
             'z': [[5, 6]]})

我想找到值为6的所有键。一种解决方案是编写一个嵌套的for循环,迭代defaultdict的键值,但我相信有更好的方法要做到这一点。

2 个答案:

答案 0 :(得分:1)

您可以使用chain.from_iterable模块中的itertools,例如:

from itertools import chain 

a = defaultdict(list,
            {'a': [[2, 3], [1, 2]],
             'b': [[5, 6]],
             'w': [[]],
             'x': [[9]],
             'z': [[5, 6]]})

keys =  [k for k, v in a.items() if 6 in chain.from_iterable(v)]
print(keys)

或者,以更紧凑的方式,您可以定义一个在defaultdict值中进行查找的函数:

def get_keys(a, key=6):
    return [k for k, v in a.items() if key in chain.from_iterable(v)]

keys = get_keys(a)
print(keys)

输出:

['b', 'z']

答案 1 :(得分:1)

如果您正在进行多次查找(以及in the comments you said,您计划进行多次查找),实际创建反向违约可能会有用:

from collections import defaultdict

inp = defaultdict(list, {'a': [[2, 3], [1, 2]], 'b': [[5, 6]], 'w': [[]], 'x': [[9]], 'z': [[5, 6]]})

res = defaultdict(set)

for key, vallist in inp.items():
    for valsublist in vallist:
        for val in valsublist:
            res[val].add(key)

然后只需访问res即可进行查找。

例如:

>>> res[6]
{'z', 'b'}

>>> res[2]
{'a'}

您将始终需要遍历所有defaultdicts值中的所有项目(这需要O(n),其中n是所有值列表中所有项目的数量)。但是(在大多数情况下)查找字典中的密钥O(1)。因此,如果您计划进行多次查询,请说k,那么多次执行迭代需要O(n*k),但将其转换为另一个dict只会O(n + k)。至少如果假设set.add操作是O(1),那应该是这种情况(除了一些 - 非常罕见的 - 病态情况)。