【问题标题】:For a list of lists, merge the dictionaries with collections.defaultdict对于列表列表,将字典与 collections.defaultdict 合并
【发布时间】:2019-03-12 16:15:57
【问题描述】:

这是一个简单的问题,但我对collections.defaultdict 的行为感到困惑。这是为了帮助我了解它是如何工作的。

这个问题是从这个有用的问题中推断出来的: How to merge a list of multiple dictionaries into a dictionary of lists?

现在假设我有一个字典列表。我想合并上述问题中详述的字典:

list_of_dictionaries2 = [[{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}], [{0:3, 1:4, 2:5, 3:6}]]

预期的答案是这样的:

correct2 = [[{0:[3523, 7245], 1:[3524, 7246, 20898], 2:[3540, 7247, 20899], 
            3:[7248, 20900], 4:[3541, 20901], 5:[3542, 7249, 20902], 6:[7250]}], 
            [{0:3, 1:4, 2:5, 3:6}]]

以前,对于单个字典列表,我们通过创建一个带有默认值作为列表的空字典来解决这个问题,即我们使用collections.defaultdict(list)

鉴于这种情况是一个列表列表,我认为另一个 for 循环将是解决方案,将字典附加到一个空列表中:

from collections import defaultdict
correct2 = defaultdict(list)

empty = []

for smaller_list in list_of_dictionaries2:
    for d in smaller_list:
        for k,v in d.items():
            correct2[k].append(v)
    empty.append(correct2)

这是非常错误的。

>>> print(empty)
[defaultdict(<class 'list'>, {0: [3523, 7245, 3], 1: [3524, 7246, 20898, 4], 
2: [3540, 7247, 20899, 5], 4: [3541, 20901], 5: [3542, 7249, 20902], 
3: [7248, 20900, 6], 6: [7250]}), defaultdict(<class 'list'>, 
{0: [3523, 7245, 3], 1: [3524, 7246, 20898, 4], 2: [3540, 7247, 20899, 5], 
4: [3541, 20901], 5: [3542, 7249, 20902], 3: [7248, 20900, 6], 6: [7250]})]

看起来所有字典都合并了。并且有两个副本。这不是我想要的。

如何为每个单独的列表执行此操作,如上所示?我在哪里理解有误?

【问题讨论】:

    标签: python python-3.x dictionary defaultdict dictionary-comprehension


    【解决方案1】:

    您实际上并没有字典列表,而是字典列表列表,并且您尝试在子列表中合并字典,因此您应该在迭代的循环中初始化 defaultdict通过主列表:

    empty = []
    for smaller_list in list_of_dictionaries2:
        correct2 = defaultdict(list)
        for d in smaller_list:
            for k,v in d.items():
                correct2[k].append(v)
        empty.append(correct2)
    

    empty 会变成:

    [defaultdict(&lt;class 'list'&gt;, {0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 4: [3541, 20901], 5: [3542, 7249, 20902], 3: [7248, 20900], 6: [7250]}), defaultdict(&lt;class 'list'&gt;, {0: [3], 1: [4], 2: [5], 3: [6]})]

    请注意,您对第二个合并 defaultdict 的预期输出不正确,因为合并后每个键的值应该是一个列表。此外,字典列表的列表应该在合并后变成defaultdicts 的列表列表,而不是defaultdicts 的列表列表。

    【讨论】:

    • 我同意你的说法,但我也相信他想看看如何将所有内容整合到一个字典中
    • @vash_the_stampede 我认为上面blshing的输出看起来是正确的,对吧?
    • @blshing 谢谢你的解释---我现在意识到我的错误。推论:为什么在这种情况下使用correct2= defaultdict(list) 而不是correct2=dict()?就这样我明白了
    • @ShanZhengYang 你的问题!不是我的 :) 我以为您正在尝试生成一个包含所有内容的默认字典
    • @vash_the_stampede 抱歉;我试图编辑问题以使其更清楚。 :)
    【解决方案2】:

    你应该像这样初始化correct2每个循环

    for smaller_list in list_of_dictionaries2:
        correct2 = defaultdict(list)
        for d in smaller_list:
            for k, v in d.items():
                correct2[k].append(v)
        empty.append(correct2)
    

    输出将是

    [defaultdict(<class 'list'>, {0: [3523, 7245], 1: [3524, 7246, 20898],
    2: [3540, 7247, 20899], 4: [3541, 20901], 5: [3542, 7249, 20902], 
    3: [7248, 20900], 6: [7250]}), 
    defaultdict(<class 'list'>, {0: [3],1: [4], 2: [5], 3: [6]})]
    

    注意 defaultdict 是可变对象

    【讨论】:

    • 这是有道理的——我觉得我可能错过了重点。为什么在这种情况下使用defaultdict(list) 而不是correct2=dict()?有性能差异吗?
    猜你喜欢
    • 2016-12-22
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 2017-04-11
    • 2021-07-29
    • 2022-01-19
    • 2020-10-12
    • 2019-04-28
    相关资源
    最近更新 更多