【问题标题】:python quickest way to merge dictionaries based on key matchpython根据键匹配合并字典的最快方法
【发布时间】:2011-11-11 17:51:02
【问题描述】:

我有 2 个字典列表。列表 A 长 34,000,列表 B 长 650,000。我本质上是根据键匹配将所有 List B 字典插入到 List A 字典中。目前,我正在做显而易见的事情,但它需要永远(说真的,就像一天)。一定有更快的方法!

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

【问题讨论】:

  • 你检查过这个问题了吗:stackoverflow.com/questions/38987/… - 我不确定你是否试图用 listB 覆盖 listA 的内容,但如果是这样,那就是你的答案。
  • 感谢 mwan100,但我将 listB 项目插入 listA 项目,而不是覆盖。此外,该海报承认,如果性能是一个问题,它不是一个很好的解决方案
  • a["ID"] 的值是否唯一?
  • DSM,仅在 A 侧。字典来自一个 ['ID'] 是主键的数据库。一个 A 有很多 B。
  • 看看这里 - wiki.python.org/moin/PythonSpeed/PerformanceTips。 “避免点”和“局部变量”部分可能会有所帮助。连同下面的答案。

标签: python dictionary


【解决方案1】:
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 的 dicts 匹配每个“ID”来避免遍历 listB 中的每个 dict 来为 listA 中的每个 dict

【讨论】:

  • dictB.setdefault([]) 引发 TypeError: unhashable type: 'list'
  • @MFB 这是setdefault('whateverthekeyis', [])
  • @MFB 实际上看起来他的意思是from collections import defaultdict; dictB = defaultdict(list)。我正在编辑答案以反映这一点。每次进行密钥查找时都需要使用setdefault,因此应为dictB.setdefault(b['ID'], []).append(b)
【解决方案2】:

这是一种可能会有所帮助的方法。详细信息由您填写。

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

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

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

举例来说,假设 A 在排序后有以下 ids

acfgjp

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

aaaabbbbcccddeeeefffggiikknnnnppppqqqrrr

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

【讨论】:

  • 雷,感谢您的出色回应。我可以澄清一下吗?将每个列表按 ID 排序后,我是恢复使用我的方法,还是采用其他方法?
【解决方案3】:

我会将 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}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-10
    • 2016-02-22
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 2014-07-10
    相关资源
    最近更新 更多