List 确保列表中的所有dict都有相同的键
我有一个字典列表,比如List 确保列表中的所有dict都有相同的键,list,dictionary,set,python,List,Dictionary,Set,Python,我有一个字典列表,比如 [{'x': 42}, {'x': 23, 'y': 5}] 并希望确保所有dict具有相同的键,如果原始dict中不存在键,则值为None。因此,上面的列表应为 [{'x': 42, 'y': None}, {'x': 23, 'y': 5}] 做这件事最漂亮、最有魅力的方式是什么?目前的做法: keys = reduce(lambda k, l: k.union(set(l)), [d.keys() for d in my_list], set()) new_li
[{'x': 42}, {'x': 23, 'y': 5}]
并希望确保所有dict具有相同的键,如果原始dict中不存在键,则值为None
。因此,上面的列表应为
[{'x': 42, 'y': None}, {'x': 23, 'y': 5}]
做这件事最漂亮、最有魅力的方式是什么?目前的做法:
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)
但特别是前两行似乎有点笨拙。想法?最简单的方法是:
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}]
我们从所有字典中的所有键创建一个集合,然后循环使用dict
s更新它们没有的任何值
使用itertools.chain.from_iterable()
的替代方法是使用functools.reduce()
(在3.x中,2.x中内置reduce()
)和操作符或
,尽管我觉得可读性较差
如果要创建新列表,而不是更新旧列表,只需将for循环替换为:
newdicts = [{key: item.get(key, None) for key in keys} for item in dicts]
这将创建一个新的字典列表,所有字典都有完整的键:
>>> 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}]
也许你应该使用命名元组而不是字典。哪个dict是“原始的”?没有“原始的”ithink@Nkosinathi:对原始dict使用
defaultdict(lambda:None)
可能会解决问题。是的。链条是“扁平的”。但是你需要从字典里取钥匙吗?如果你只是在dict上迭代,你会得到键。。。ieset(chain({1:2},{3:4}))
给出了set([1,3])
@andrewcooke这是真的,改变了。有趣的生成器嵌套!我想我以前从未见过这种结构,老实说,我不太确定我是否理解它为什么会起作用。。。需要详细说明吗?它与嵌套for循环相同,从左到右阅读它,如:对于l中的d:对于d中的k:k
。但是k在左边,因为它是一个列表。所以它会遍历l中的每一个字典,然后遍历该字典中的每一个键。另外,我也懒得检查,但我想知道d.update((k,None)for k in all_key如果k不在d中)
是否比d.update((k,None)for k in all_key-d.viewkeys())
。不错,尽管chain
似乎更快(列表中有约3000个dict,每个都有约10个键):%timeit set设置(k for d in l for k in m)
:1000个循环,每个循环的最佳时间为3:4.86毫秒
%timeit set(chain.from_iterable(l))
:1000个循环,每个循环的最佳时间为3:2.61毫秒
@Nkosinathi我将其更改为链。从
,您是正确的,它会好得多。
>>> 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}]