【问题标题】:Make sure all dicts in a list have the same keys确保列表中的所有 dicts 具有相同的键
【发布时间】:2012-05-15 23:34:07
【问题描述】:

我有一个像字典这样的列表

[{'x': 42}, {'x': 23, 'y': 5}]

并希望确保所有 dicts 具有相同的键,如果原始 dict 中不存在该键,则其值为 None。所以上面的列表应该变成

[{'x': 42, 'y': None}, {'x': 23, 'y': 5}]

什么是最漂亮和最pythonic的方式来做到这一点?目前的做法:

keys = reduce(lambda k, l: k.union(set(l)), [d.keys() for d in my_list], set())
new_list = [dict.fromkeys(keys, None) for i in xrange(len(my_list))]
for i, l in enumerate(my_list):
    new_list[i].update(l)

但尤其是前两行似乎有点笨拙。想法?

【问题讨论】:

  • 也许你应该使用命名元组而不是字典。
  • 哪个字典是“原始的”?
  • 我认为没有'original'
  • @Nkosinathi:将defaultdict(lambda: None) 用于您的原始字典可能会解决问题。

标签: list dictionary set python


【解决方案1】:
>>> from itertools import chain 
>>> l = [{'x': 42}, {'x': 23, 'y': 5}]
>>> all_keys = set(chain.from_iterable(l))   
>>> for d in l:
        d.update((k,None) for k in all_keys-d.viewkeys())


>>> l
[{'y': None, 'x': 42}, {'y': 5, 'x': 23}]

【讨论】:

  • 有趣的生成器嵌套!我想我以前从未见过这种结构,老实说,我不太确定我是否理解它为什么会起作用……想详细说明一下吗?
  • 和嵌套的for循环一样,从左到右读起来像:for d in l: for k in d: k。但是 k 在左侧,因为它是一个列表理解。所以它会遍历 l 中的每个字典,然后遍历该字典中的每个键。
  • +1。另外,我也懒得去查了,不知道d.update((k,None) for k in all_keys if k not in d)会不会比d.update((k,None) for k in all_keys-d.viewkeys())表现更好。
  • 很好,虽然chain 似乎更快(列出约 3000 个约 10 个键的字典):%timeit set(k for d in l for k in m)1000 loops, best of 3: 4.86 ms per loop%timeit set(chain.from_iterable(l))1000 loops, best of 3: 2.61 ms per loop
  • @Nkosinathi 改为chain.from_iterable,你说得对,它好多了。
【解决方案2】:

最简单的方法:

from itertools import chain

dicts = [{'x': 42}, {'x': 23, 'y': 5}]

keys = set(chain.from_iterable(dicts))
for item in dicts:
     item.update({key: None for key in keys if key not in item})

给我们:

[{'y': None, 'x': 42}, {'y': 5, 'x': 23}]

我们从所有字典中的所有键中创建一个集合,然后循环通过 dicts 更新它们没有的任何值。

使用itertools.chain.from_iterable() 的替代方法是使用functools.reduce()(在3.x 中,在2.x 中内置reduce())和operator.or_ 使用reduce(or_, [dict.keys() for dict in dicts]),虽然我觉得这更少可读。

如果您想创建一个新列表,而不是更新旧列表,只需将 for 循环替换为:

newdicts = [{key: item.get(key, None) for key in keys} for item in dicts]

【讨论】:

  • 是的。链条“变平”。但是你需要从字典中拉出钥匙吗?如果你只是迭代字典,你会得到钥匙......即set(chain({1: 2},{3: 4}))set([1, 3])
  • @andrewcooke 这是真的,改变了。
【解决方案3】:

这会创建一个新的字典列表,所有字典都有完整的键:

>>> import itertools as it
>>> l = [{'x': 42}, {'x': 23, 'y': 5}]
>>> all_keys = set(it.chain.from_iterable(l))
>>> [dict((k, a.get(k, None)) for k in all_keys) for a in l]
[{'x': 42, 'y': None}, {'x': 23, 'y': 5}]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    相关资源
    最近更新 更多