python基于密钥匹配合并字典的最快方法

时间:2011-09-06 23:34:05

标签: python dictionary

我有2个词典列表。列表A长34,000,列表B长650,000。我基本上是根据键匹配将所有List B dicts插入到List A dicts中。目前,我做的很明显,但它永远服用(严肃地说,就像一天)。必须有一个更快的方法!

for a in listA:
    a['things'] = []
    for b in listB:
        if a['ID'] == b['ID']:
            a['things'].append(b)

3 个答案:

答案 0 :(得分:4)

from collections import defaultdict
dictB = defaultdict(list)
for b in listB:
    dictB[b['ID']].append(b)

for a in listA:
    a['things'] = []
    for b in dictB[a['ID']]:
        a['things'].append(b)

这会将你的算法从O(n * m)变为O(m)+ O(n),其中n = len(listA),m = len(listB)

基本上它通过'预先计算'从listB匹配每个'ID'

的每个字典来避免循环遍历listB中每个字典的listB中的每个字典

答案 1 :(得分:1)

这是一种可能有所帮助的方法。我会留给你填写详细信息。

你的代码很慢,因为它是一个O(n ^ 2)算法,将每个A与每个B进行比较。

如果您首先按id(这些是O(nlogn))操作对listA和listB中的每一个进行排序,那么您可以轻松地遍历A和B的排序版本(这将是线性时间)。

当您必须在非常大的数据集上进行外部合并时,这种方法很常见。 Mihai的答案更适合内部合并,你只需按id(在内存中)索引所有内容。如果你有内存来保存这些额外的结构,并且字典查找是恒定的时间,那么这种方法可能会更快,更不用说更简单了。 :)

举个例子,假设A在排序后有

acfgjp

和B有这些id,再次排序后

aaaabbbbcccddeeeefffggiikknnnnppppqqqrrr

奇怪的是,这个想法是将索引保持在A和B中(我知道这听起来不是Pythonic)。首先,您要查看A中的a和B中的a。因此,您将通过B将所有a添加到a的“事物”数组中。一旦你在B中消耗a,你就在A中向上移动一个c。但是B中的下一个项目是b,小于c,所以你必须跳过b。然后你到达B中的c,这样你就可以开始为c添加“东西”了。以这种方式继续,直到两个列表都用尽。只需一次通过。 :)

答案 2 :(得分:0)

我将ListA和ListB转换为字典,而不是以ID为键的字典。然后使用python的快速字典查找来附加数据是一件简单的事情:

from collections import defaultdict

class thingdict(dict):
    def __init__(self, *args, **kwargs):
        things = []
        super(thingdict,self).__init__(*args, things=things, **kwargs)

A = defaultdict(thingdict)
A[1] = defaultdict(list)
A[2] = defaultdict(list, things=[6])  # with some dummy data
A[3] = defaultdict(list, things=[7])

B = {1: 5, 2: 6, 3: 7, 4: 8, 5: 9}

for k, v in B.items():
    # print k,v
    A[k]['things'].append(v)

print A
print B

返回:

defaultdict(<class '__main__.thingdict'>, {
    1: defaultdict(<type 'list'>, {'things': [5]}),
    2: defaultdict(<type 'list'>, {'things': [6, 6]}),
    3: defaultdict(<type 'list'>, {'things': [7, 7]}),
    4: {'things': [8]},
    5: {'things': [9]}
})
{1: 5, 2: 6, 3: 7, 4: 8, 5: 9}