【问题标题】:Merge dictionaries into dictionary of lists将字典合并到列表字典中
【发布时间】:2017-04-11 02:46:33
【问题描述】:

我有三个字典:

dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'b': 3, 'c': 4}
dict3 = {'c': 4, 'd': 4}

我想将它们“合并”到列表字典中

merged_dict = {'a':[1, np.nan, np.nan],
               'b':[2, 3, np.nan],
               'c':[3, 4, 4],
               'd':[np.nan, np.nan, 4]}

有些字典中有一些键,而另一些则没有,这使得循环有点痛苦。想知道最干净的方法是什么。

【问题讨论】:

  • 为什么 d 键中的 4 排在列表中其他元素之后?
  • 因为前两个字典中不存在
  • 我认为您只是硬着头皮遍历字典和键。您可能需要迭代一次以收集所有密钥。

标签: python numpy dictionary merge


【解决方案1】:

如 cmets 中所述,您需要首先遍历所有字典以收集所有键,否则无法知道每个单独的字典中缺少哪些键。然后你可以用字典理解来构建merged_dict

import numpy as np

dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'b': 3, 'c': 4}
dict3 = {'c': 4, 'd': 4}

all_dicts = (dict1, dict2, dict3)

keys = {k for d in all_dicts for k in d}
merged_dict = {k: [d.get(k, np.nan) for d in all_dicts] for k in keys} 
print(merged_dict)   

输出

{'a': [1, nan, nan], 'b': [2, 3, nan], 'c': [3, 4, 4], 'd': [nan, nan, 4]}

可以将集合理解放在 dict 理解中,但我认为这会使代码更难阅读。

merged_dict = {k: [d.get(k, np.nan) for d in all_dicts] 
    for k in {k for d in all_dicts for k in d}}

实际上,集合 comp 中的双 for 循环并不是那么有效。对于小型 dicts 可能并不重要,但如果 dicts 很大,使用 set.update 方法以 C 速度执行其中一个循环会更有效:

keys = set()
for d in all_dicts:
    keys.update(d.keys())

这可能更好:

keys = set().union(*all_dicts)

谢谢,丹。 D 为那个建议!

这是另一种方式,使用itertools

from itertools import chain
keys = set(chain.from_iterable(dicts))

【讨论】:

  • @DanD。好点子!我很惊讶我自己没有这么想。 :) 现在我很想写一个 timeit 测试来比较所有这些变化,包括 Brendan 的......
【解决方案2】:

pandas 在解析字典和合并字典方面做得很好。你可以这样做。

设置

import pandas as pd

dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'b': 3, 'c': 4}
dict3 = {'c': 4, 'd': 4}

解决方案

df = pd.concat([pd.Series(d) for d in [dict1, dict2, dict3]], axis=1)
df

获取您要查找的字典。

df.T.to_dict('list')

{'a': [1.0, nan, nan],
 'b': [2.0, 3.0, nan],
 'c': [3.0, 4.0, 4.0],
 'd': [nan, nan, 4.0]}

【讨论】:

  • 我实际上最终接受了这一点并选择了这条路线,因为我最终还是要转换为 Pandas DataFrame,这对我来说更容易阅读。我敢打赌另一个答案会更快,所以我会将其保留为选定的答案,除非最终更快,但这段代码对我来说更容易阅读。
  • @Chris 另一个答案更快。但我同意,这更直观。
  • 我对选择哪一个感到很矛盾。如果这个最终得到更多的选票,我会改变我的选择。
  • 不要冲突。实际上,我会选择其他答案,因为它更直接地回答了您的问题。不管怎样,对我来说都无所谓。就积分而言,我会从回答很多问题中得到很多。我很高兴看到您积极选择答案。我觉得这要重要得多。
【解决方案3】:

应该这样做。

from itertools import chain

dicts = [dict1, dict2, dict3]
keys = set(chain(*[d.keys() for d in dicts]))
merged_dict = {k: [d.get(k, np.nan) for d in dicts] for k in keys}

【讨论】:

  • 这与上面的答案基本相同,并且 100% 正确,但解释少了一点,所以我选择那个,但我赞成这个,因为它也是正确的。
猜你喜欢
  • 2011-03-30
  • 1970-01-01
  • 2020-10-12
  • 2019-03-12
  • 1970-01-01
  • 2013-02-19
  • 1970-01-01
相关资源
最近更新 更多