将字典列表中相同键的值合并为一个列表

18

我有一个字典列表,格式如下:

foo = [
    {'a': 'x', 'b': 'y', 'c': 'z'},
    {'a': 'j', 'c': 'z'}
]

我想将这个字典列表分组为一个单一的字典,如下所示:

bar = {
    'a': ['x', 'j'],
    'b': ['y', None],
    'c': ['z', 'z']
}

目前我所做的是循环遍历foo中的所有字典,创建一个键列表,然后再次循环同样的内容来创建bar。 我想知道是否有更简单的方法来完成这个任务。 有人可以帮忙吗?


foo只有两个字典还是可以有任意数量的字典? - Jean-François Fabre
@Jean-FrançoisFabre 可以有超过两个。 - akhilsp
3个回答

34
bar = {
    k: [d.get(k) for d in foo]
    for k in set().union(*foo)
}

需要搜索的内容:

  • Python列表推导式
  • Python字典推导式
  • Python星号(*)
  • Python字典的get方法
  • Python集合的并集操作

6
好的解决方案,可以附上一些解释。我喜欢 set().union(*foo) 这部分。 - Jean-François Fabre
3
@Alex Hall 加一分,因为添加了谷歌搜索技巧。 - Tokci
有使用 d.get(k) 而不是 d[k] 的原因吗?编辑:找到答案:为什么要使用 dict.get(key) 而不是 dict[key]? - mins
1
@mins - 使用d.get(k)- 因为键k可能不存在。 - Daniel Hao

11

我只是想在这里补充一下Alex Hall的解决方案,以便它不会返回很多“None”值:

def merge_dictionary_list(dict_list):
  return {
    k: [d.get(k) for d in dict_list if k in d] # explanation A
    for k in set().union(*dict_list) # explanation B
  }

解释:

  • {} 中的整个内容都是一个字典解析。
  • 解释A: 遍历字典列表中的所有元素,如果当前正在评估的字典(d)实际上有该键,则获取当前键 k 的值。

OBS: 如果没有 if k in d 表达式,则在字典列表中包含不同类型的键时,可能会将许多 None 值附加到数组中。

  • 解释B: 从字典列表中获取所有键,并使用 set().union 将它们合并为不同的单元。最后,我们只能在集合数据结构中拥有不同的元素。

如果你想按照传统方式进行操作,就使用以下代码:

def merge_list_of_dictionaries(dict_list):
  new_dict = {}
  for d in dict_list:
    for d_key in d:
      if d_key not in new_dict:
        new_dict[d_key] = []
      new_dict[d_key].append(d[d_key])
  return new_dict

我认为第一个解决方案看起来更优雅,但第二个解决方案更易于阅读。

敬祝好运 :)


4
我会采取两步方法来完成这个操作:
  1. Collect all keys into a single iterable:

    >>> import operator
    >>> from functools import reduce
    >>> all_keys = reduce(operator.or_, (d.keys() for d in foo))
    >>> all_keys
    {'a', 'b', 'c'}
    
  2. Use a dict comprehension to create the desired result:

    >>> bar = {key: [d.get(key) for d in foo] for key in all_keys}
    >>> bar
    {'a': ['x', 'j'], 'b': ['y', None], 'c': ['z', 'z']}
    

1
不错。我可以建议使用 all_keys = reduce(operator.or_, map(dict.keys,foo)) 吗? - Jean-François Fabre
1
这只能在 Python 3 上运行。 - Alex Hall
@Jean-FrançoisFabre 这是一个可行的替代方案。我选择避免使用 map 的原因是它强制我明确声明类 - dict.keys。另一方面,生成器表达式也适用于字典子类或任何其他具有 .keys() 函数的对象。 - Aran-Fey
@AlexHall 可能吧。如果子类重写了 keys 函数,谁知道会发生什么。但是让我们放弃这个讨论;最终的差异是如此微小,以至于归结为个人偏好。 - Aran-Fey
2
你也可以使用set(chain.from_iterable(foo))来获取所有键的集合。 - poke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接