关于词典:python基于值匹配合并字典的最快方法

python quickest way to merge dictionaries based on key match

我有两本字典。清单A长34000,清单B长650000。我基本上是将所有列表B的dicts插入到列表A的dicts中,它基于一个键匹配。目前,我做的很明显,但它永远(认真地说,就像一天)。一定有更快的方法!

1
2
3
4
5
for a in listA:
    a['things'] = []
    for b in listB:
        if a['ID'] == b['ID']:
            a['things'].append(b)


1
2
3
4
5
6
7
8
9
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)

基本上,它避免了通过"预先计算"列表B中的哪些dict与每个"id"匹配来为列表A中的每个dict循环遍历列表B中的每个dict。


这是一个可能有帮助的方法。我会留给你来填写细节。

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

如果先按ID对lista和listb中的每一个进行排序(这是o(nlogn))操作,那么您可以轻松地遍历已排序的a和b版本(这将是线性时间)。

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

举例来说,我们假设A在排序后具有以下ID

1
acfgjp

B有这些身份证,排序后又有一次

1
aaaabbbbcccddeeeefffggiikknnnnppppqqqrrr

奇怪的是,这个想法可以让索引保持在A和B中(我知道这听起来不是很像Python)。首先,你看到的是a中的a和b中的a,所以你走过b,把a的所有值加到a的"things"数组中。一旦你把A在B中耗尽,你就向上移动A中的一个,到达c。但是B中的下一个项目是b,它小于c,所以你必须跳过B。然后你到达B中的c,这样你就可以开始为C添加"东西"。继续这样直到两个列表都用完。一个通行证。:)


我将把lista和listb转换成字典,用i d作为键的字典。然后,使用python的快速字典查找附加数据是一件简单的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

这种回报:

1
2
3
4
5
6
7
8
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}