用Python相交两个词典

nic*_*ole 62 python iteration dictionary intersection

我正在研究一个倒排索引的搜索程序.索引本身是一个字典,其键是术语,其值本身是短文档的字典,ID号作为键,其文本内容作为值.

为了对两个术语执行"AND"搜索,我需要与他们的帖子列表(词典)相交.在Python中做这个的明确(不一定是过于聪明)的方法是什么?我开始尝试很长的路iter:

p1 = index[term1]  
p2 = index[term2]
i1 = iter(p1)
i2 = iter(p2)
while ...  # not sure of the 'iter != end 'syntax in this case
...
Run Code Online (Sandbox Code Playgroud)

Phi*_*oud 104

一个鲜为人知的事实是你不需要构造sets来做到这一点:

在Python 2中:

In [78]: d1 = {'a': 1, 'b': 2}

In [79]: d2 = {'b': 2, 'c': 3}

In [80]: d1.viewkeys() & d2.viewkeys()
Out[80]: {'b'}
Run Code Online (Sandbox Code Playgroud)

在Python 3中替换viewkeyskeys; 这同样适用于viewvaluesviewitems.

来自以下文件viewitems:

In [113]: d1.viewitems??
Type:       builtin_function_or_method
String Form:<built-in method viewitems of dict object at 0x64a61b0>
Docstring:  D.viewitems() -> a set-like object providing a view on D's items
Run Code Online (Sandbox Code Playgroud)

对于较大的dicts,这也比构造sets然后相交它们稍快一些:

In [122]: d1 = {i: rand() for i in range(10000)}

In [123]: d2 = {i: rand() for i in range(10000)}

In [124]: timeit d1.viewkeys() & d2.viewkeys()
1000 loops, best of 3: 714 µs per loop

In [125]: %%timeit
s1 = set(d1)
s2 = set(d2)
res = s1 & s2

1000 loops, best of 3: 805 µs per loop

For smaller `dict`s `set` construction is faster:

In [126]: d1 = {'a': 1, 'b': 2}

In [127]: d2 = {'b': 2, 'c': 3}

In [128]: timeit d1.viewkeys() & d2.viewkeys()
1000000 loops, best of 3: 591 ns per loop

In [129]: %%timeit
s1 = set(d1)
s2 = set(d2)
res = s1 & s2

1000000 loops, best of 3: 477 ns per loop
Run Code Online (Sandbox Code Playgroud)

我们在这里比较纳秒,这对您来说可能或不重要.在任何情况下,你都会回来set,所以使用viewkeys/ keys消除了一些混乱.

  • `viewkeys()`是"2.7版本的新功能" (4认同)
  • 不知何故,这最终比 `set(d1.keys()) &amp; set(d2.keys())` 方法计算速度慢*一点*(~12%)。但是,我不明白为什么会这样。 (2认同)

Jam*_*mes 70

您可以轻松计算集合的交集,因此可以从键创建集合并将它们用于交集:

keys_a = set(dict_a.keys())
keys_b = set(dict_b.keys())
intersection = keys_a & keys_b # '&' operator is used for set intersection
Run Code Online (Sandbox Code Playgroud)

  • 在python 3中,.keys()视图已经是一个集合,因此您可以直接执行inter = dict_a.keys()和dict_b.keys()。 (12认同)

emn*_*oor 66

In [1]: d1 = {'a':1, 'b':4, 'f':3}

In [2]: d2 = {'a':1, 'b':4, 'd':2}

In [3]: d = {x:d1[x] for x in d1 if x in d2}

In [4]: d
Out[4]: {'a': 1, 'b': 4}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是答案,因为这是唯一一个以简单的方式显示如何获得交叉点,而不是键列表的方法. (10认同)

dcc*_*lag 14

在Python 3中,您可以使用

intersection = dict(dict1.items() & dict2.items())
union = dict(dict1.items() | dict2.items())
difference = dict(dict1.items() ^ dict2.items())
Run Code Online (Sandbox Code Playgroud)

  • 对于 `dict1 = {1: 1, 2:2}` 和 `dict2 = {2:4, 3:3}`,`intersection == set()`。可能这不是 OP 想要的。 (4认同)
  • 仅当所有值都是可哈希的时,此方法才有效。 (2认同)