Python - 展平字典列表
Posted
技术标签:
【中文标题】Python - 展平字典列表【英文标题】:Python - Flatten the list of dictionaries 【发布时间】:2018-07-19 22:07:09 【问题描述】:词典列表:
data = [
'a':'l':'Apple',
'b':'Milk',
'd':'Meatball',
'b':'favourite':'coke',
'dislike':'juice'
,
'a':'l':'Apple1',
'b':'Milk1',
'd':'Meatball2',
'b':'favourite':'coke2',
'dislike':'juice3'
, ...
]
我需要加入所有嵌套字典以达到预期输出:
['d': 'Meatball', 'b': 'Milk', 'l': 'Apple', 'dislike': 'juice', 'favourite': 'coke',
'd': 'Meatball2', 'b': 'Milk1', 'l': 'Apple1', 'dislike': 'juice3', 'favourite': 'coke2']
我尝试嵌套列表理解,但无法将 dict 连接在一起:
L = [y for x in data for y in x.values()]
print (L)
['d': 'Meatball', 'b': 'Milk', 'l': 'Apple',
'dislike': 'juice', 'favourite': 'coke',
'd': 'Meatball2', 'b': 'Milk1', 'l': 'Apple1',
'dislike': 'juice3', 'favourite': 'coke2']
我正在寻找最快的解决方案。
【问题讨论】:
how-to-merge-two-dictionaries-in-a-single-expression 会有所帮助。 【参考方案1】:您可以使用itertools.chain
:
>>> from itertools import chain
# timeit: ~3.40
>>> [dict(chain(*map(dict.items, d.values()))) for d in data]
['l': 'Apple',
'b': 'Milk',
'd': 'Meatball',
'favourite': 'coke',
'dislike': 'juice',
'l': 'Apple1',
'b': 'Milk1',
'dislike': 'juice3',
'favourite': 'coke2',
'd': 'Meatball2']
chain
、map
、*
的使用使这个表达式成为以下双重嵌套理解的简写,它实际上在我的系统 (Python 3.5.2) 上执行得更好,而且不会更长:
# timeit: ~2.04
[k: v for x in d.values() for k, v in x.items() for d in data]
# Or, not using items, but lookup by key
# timeit: ~1.67
[k: x[k] for x in d.values() for k in x for d in data]
注意:
RoadRunner's 循环和更新方法在timeit: ~1.37
上优于这两种单行方法
【讨论】:
我喜欢你的公平行为,因为添加了另一个更好的解决方案的时间,所以不要重新接受;)谢谢。 @jezrael 谢谢,不,不需要隐藏这个事实。比较这 3 种风格如此不同的方法很有趣,并看到简单的循环击败了理解,尤其是内置和 itertools 的厨房水槽:)dict(chain(*map(...
的一个更易读的替代方案是[ChainMap(*d.values()) for d in data]
。不过,它比其他方法慢。
如果我想展平[k: v for x in d.values() for k, v in x.items() for d in data]
的输出,这是一个字典列表,它会给出错误TypeError: descriptor 'items' requires a 'dict' object but received a 'str'
?这个结果就像输入数据一样。【参考方案2】:
您可以使用 2 个嵌套循环和dict.update()
将内部字典添加到临时字典并将其添加到末尾:
L = []
for d in data:
temp =
for key in d:
temp.update(d[key])
L.append(temp)
# timeit ~1.4
print(L)
哪些输出:
['l': 'Apple', 'b': 'Milk', 'd': 'Meatball', 'favourite': 'coke', 'dislike': 'juice', 'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2', 'favourite': 'coke2', 'dislike': 'juice3']
【讨论】:
【参考方案3】:您可以使用functools.reduce
和一个简单的列表推导来展平字典列表
>>> from functools import reduce
>>> data = ['b': 'dislike': 'juice', 'favourite': 'coke', 'a': 'l': 'Apple', 'b': 'Milk', 'd': 'Meatball', 'b': 'dislike': 'juice3', 'favourite': 'coke2', 'a': 'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2']
>>> [reduce(lambda x,y: **x,**y,d.values()) for d in data]
>>> ['dislike': 'juice', 'l': 'Apple', 'd': 'Meatball', 'b': 'Milk', 'favourite': 'coke', 'dislike': 'juice3', 'l': 'Apple1', 'd': 'Meatball2', 'b': 'Milk1', 'favourite': 'coke2']
时间基准如下:
>>> import timeit
>>> setup = """
from functools import reduce
data = ['b': 'dislike': 'juice', 'favourite': 'coke', 'a': 'l': 'Apple', 'b': 'Milk', 'd': 'Meatball', 'b': 'dislike': 'juice3', 'favourite': 'coke2', 'a': 'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2']
"""
>>> min(timeit.Timer("[reduce(lambda x,y: **x,**y,d.values()) for d in data]",setup=setup).repeat(3,1000000))
>>> 1.525032774952706
我机器上其他答案的时间基准
>>> setup = """
data = ['b': 'dislike': 'juice', 'favourite': 'coke', 'a': 'l': 'Apple', 'b': 'Milk', 'd': 'Meatball', 'b': 'dislike': 'juice3', 'favourite': 'coke2', 'a': 'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2']
"""
>>> min(timeit.Timer("[k: v for x in d.values() for k, v in x.items() for d in data]",setup=setup).repeat(3,1000000))
>>> 2.2488374650129117
>>> min(timeit.Timer("[k: x[k] for x in d.values() for k in x for d in data]",setup=setup).repeat(3,1000000))
>>> 1.8990078769857064
>>> code = """
L = []
for d in data:
temp =
for key in d:
temp.update(d[key])
L.append(temp)
"""
>>> min(timeit.Timer(code,setup=setup).repeat(3,1000000))
>>> 1.4258553800173104
>>> setup = """
from itertools import chain
data = ['b': 'dislike': 'juice', 'favourite': 'coke', 'a': 'l': 'Apple', 'b': 'Milk', 'd': 'Meatball', 'b': 'dislike': 'juice3', 'favourite': 'coke2', 'a': 'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2']
"""
>>> min(timeit.Timer("[dict(chain(*map(dict.items, d.values()))) for d in data]",setup=setup).repeat(3,1000000))
>>> 3.774383604992181
【讨论】:
【参考方案4】:如果您的嵌套字典只有“a”和“b”键,那么我建议使用以下解决方案,我发现它快速且易于理解(出于可读性目的):
L = [x['a'] for x in data]
b = [x['b'] for x in data]
for i in range(len(L)):
L[i].update(b[i])
# timeit ~1.4
print(L)
【讨论】:
以上是关于Python - 展平字典列表的主要内容,如果未能解决你的问题,请参考以下文章