如何将多个字典的列表合并到列表字典中?
How to merge a list of multiple dictionaries into a dictionary of lists?
我在 Python3.x 中有以下词典列表:
list_of_dictionaries = [{0:3523, 1:3524, 2:3540, 4:3541, 5:3542},
{0:7245, 1:7246, 2:7247, 3:7248, 5:7249, 6:7250},
{1:20898, 2:20899, 3:20900, 4:20901, 5:20902}]
在本例中,它是一个包含三个词典的列表。
我想有效地将其合并到一个以列表为值的字典中;这是正确答案:
correct = {0:[3523, 7245], 1:[3524, 7246, 20898], 2:[3540, 7247, 20899],
3:[7248, 20900], 4:[3541, 20901], 5:[3542, 7249, 20902], 6:[7250]}
我的第一个想法是这样的列表理解:
dict(pair for dictionary in list_of_dictionaries for pair in dictionary.items())
但这是错误的,因为它不包括值列表:
{0: 7245, 1: 20898, 2: 20899, 4: 20901, 5: 20902, 3: 20900, 6: 7250}
我也很担心如何尽可能高效地创建价值列表。它也可能无法扩展到大型 lists/large 词典。
我怎样才能做到这一点?
defaultdict
您可以使用 collections.defaultdict
。你的字典理解永远不会起作用,因为你没有定义任何列表。这可能比使用字典理解更有效,后者涉及为每个唯一键迭代每个字典。
from collections import defaultdict
dd = defaultdict(list)
for d in list_of_dictionaries:
for k, v in d.items():
dd[k].append(v)
结果:
print(dd)
defaultdict(list,
{0: [3523, 7245],
1: [3524, 7246, 20898],
2: [3540, 7247, 20899],
4: [3541, 20901],
5: [3542, 7249, 20902],
3: [7248, 20900],
6: [7250]})
词典理解
字典理解是可能的,但这需要计算键的并集并为每个键迭代字典列表:
allkeys = set().union(*list_of_dictionaries)
res = {k: [d[k] for d in list_of_dictionaries if k in d] for k in allkeys}
{0: [3523, 7245],
1: [3524, 7246, 20898],
2: [3540, 7247, 20899],
3: [7248, 20900],
4: [3541, 20901],
5: [3542, 7249, 20902],
6: [7250]}
时间复杂度
考虑这些条款:
n = sum(map(len, list_of_dictionaries))
m = len(set().union(*list_of_dictionaries))
k = len(list_of_dictionaries)
在这种情况下,defaultdict
解决方案的复杂度为 O(n),而字典理解的复杂度为 O(mk), 其中 mk >= n.
您首先需要展平字典:
flattened_pairs = (
pair for dictionary in list_of_dictionaries for pair in dictionary.items()
)
然后您可以使用 itertools.groupby
对值进行分组。它期望值按键排序。
key_fn = lambda pair: pair[0]
merged = {
k: [pair[1] for pair in g]
for k, g in groupby(
sorted(flattened_pairs, key=key_fn),
key=key_fn
)
}
print(merged)
输出:
{0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 3:
[7248, 20900], 4: [3541, 20901], 5: [3542, 7249, 20902], 6: [7250]}
为什么不直接使用 for
循环?例如:
final = {}
for i in list_of_dictionaries:
for k in i:
if not k in final:
final[k] = []
final[k].append(i[k])
print(final)
最终输出为:
{0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 4: [3541, 20901], 5: [3542, 7249, 20902], 3: [7248, 20900], 6: [7250]}
使用 groupby 和 itemgetter 我们可以首先创建一个表示每个子字典的 keys and values
的平面元组列表。然后我们可以在我们排序的新列表上使用 groupby。从那里我们可以使用 k
和 list(g)
的 index[1]
中的项目创建我们的新字典
from itertools import groupby
from operator import itemgetter
d = {}
new_lod = sorted([(j, i[j]) for i in lod for j in i], key=itemgetter(0))
for k, g in groupby(new_lod, key=itemgetter(0)):
d[k] = [i[1] for i in list(g)]
# {0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 3: [7248, 20900], 4: [3541, 20901], 5: [3542, 7249, 20902], 6: [7250]}
我在 Python3.x 中有以下词典列表:
list_of_dictionaries = [{0:3523, 1:3524, 2:3540, 4:3541, 5:3542},
{0:7245, 1:7246, 2:7247, 3:7248, 5:7249, 6:7250},
{1:20898, 2:20899, 3:20900, 4:20901, 5:20902}]
在本例中,它是一个包含三个词典的列表。
我想有效地将其合并到一个以列表为值的字典中;这是正确答案:
correct = {0:[3523, 7245], 1:[3524, 7246, 20898], 2:[3540, 7247, 20899],
3:[7248, 20900], 4:[3541, 20901], 5:[3542, 7249, 20902], 6:[7250]}
我的第一个想法是这样的列表理解:
dict(pair for dictionary in list_of_dictionaries for pair in dictionary.items())
但这是错误的,因为它不包括值列表:
{0: 7245, 1: 20898, 2: 20899, 4: 20901, 5: 20902, 3: 20900, 6: 7250}
我也很担心如何尽可能高效地创建价值列表。它也可能无法扩展到大型 lists/large 词典。
我怎样才能做到这一点?
defaultdict
您可以使用 collections.defaultdict
。你的字典理解永远不会起作用,因为你没有定义任何列表。这可能比使用字典理解更有效,后者涉及为每个唯一键迭代每个字典。
from collections import defaultdict
dd = defaultdict(list)
for d in list_of_dictionaries:
for k, v in d.items():
dd[k].append(v)
结果:
print(dd)
defaultdict(list,
{0: [3523, 7245],
1: [3524, 7246, 20898],
2: [3540, 7247, 20899],
4: [3541, 20901],
5: [3542, 7249, 20902],
3: [7248, 20900],
6: [7250]})
词典理解
字典理解是可能的,但这需要计算键的并集并为每个键迭代字典列表:
allkeys = set().union(*list_of_dictionaries)
res = {k: [d[k] for d in list_of_dictionaries if k in d] for k in allkeys}
{0: [3523, 7245],
1: [3524, 7246, 20898],
2: [3540, 7247, 20899],
3: [7248, 20900],
4: [3541, 20901],
5: [3542, 7249, 20902],
6: [7250]}
时间复杂度
考虑这些条款:
n = sum(map(len, list_of_dictionaries))
m = len(set().union(*list_of_dictionaries))
k = len(list_of_dictionaries)
在这种情况下,defaultdict
解决方案的复杂度为 O(n),而字典理解的复杂度为 O(mk), 其中 mk >= n.
您首先需要展平字典:
flattened_pairs = (
pair for dictionary in list_of_dictionaries for pair in dictionary.items()
)
然后您可以使用 itertools.groupby
对值进行分组。它期望值按键排序。
key_fn = lambda pair: pair[0]
merged = {
k: [pair[1] for pair in g]
for k, g in groupby(
sorted(flattened_pairs, key=key_fn),
key=key_fn
)
}
print(merged)
输出:
{0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 3: [7248, 20900], 4: [3541, 20901], 5: [3542, 7249, 20902], 6: [7250]}
为什么不直接使用 for
循环?例如:
final = {}
for i in list_of_dictionaries:
for k in i:
if not k in final:
final[k] = []
final[k].append(i[k])
print(final)
最终输出为:
{0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 4: [3541, 20901], 5: [3542, 7249, 20902], 3: [7248, 20900], 6: [7250]}
使用 groupby 和 itemgetter 我们可以首先创建一个表示每个子字典的 keys and values
的平面元组列表。然后我们可以在我们排序的新列表上使用 groupby。从那里我们可以使用 k
和 list(g)
index[1]
中的项目创建我们的新字典
from itertools import groupby
from operator import itemgetter
d = {}
new_lod = sorted([(j, i[j]) for i in lod for j in i], key=itemgetter(0))
for k, g in groupby(new_lod, key=itemgetter(0)):
d[k] = [i[1] for i in list(g)]
# {0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 3: [7248, 20900], 4: [3541, 20901], 5: [3542, 7249, 20902], 6: [7250]}