提问人:Bella Grubb 提问时间:8/19/2023 最后编辑:Bella Grubb 更新时间:8/19/2023 访问量:90
使用嵌套 for 循环扁平化数据结构的替代方法
Alternatives to using nested for loops to flatten data structure
问:
我有一个嵌套的数据结构:字典中包含许多级别的字典列表。例如:
{‘L1’:
‘L2’:
{‘L3’: [{‘a’: 1, ‘b’: 2}, {‘c’: 1, ‘d’: 2}]}
Etc …
}
我想要一个输出,它使列表的内部列表扁平化,每个级别的外部元素。例如
L1、L2、L3、a、1、b、2
L1、L2、L3、c、1、d、2
等。。。
除了使用嵌套的 for 循环之外,有没有一种更“pythonic”和更有效的方法来实现结果?
嵌套 for 循环,当数据结构较大时,它可以工作但速度很慢
答:
1赞
Sash Sinha
8/19/2023
#1
考虑使用递归函数:
from itertools import chain
from typing import Iterator, Optional, Union
def flatten(
d: dict,
keys: Optional[list[Union[str, int]]] = None
) -> Iterator[list[Union[str, int]]]:
"""Recursively flattens a nested dictionary structure into a list of lists.
Args:
d: The input nested dictionary to flatten.
keys: A list of keys from the parent dictionaries.
Yields:
Iterator[list[Union[str, int]]]: A list containing the flattened elements.
"""
if keys is None:
keys = []
for k, v in d.items():
new_keys = keys + [k]
if isinstance(v, dict):
yield from flatten(v, new_keys)
elif isinstance(v, list):
for item in v:
flattened_items = chain.from_iterable(item.items())
yield new_keys + list(flattened_items)
else:
yield new_keys + [v]
def main() -> None:
data = {'L1': {'L2': {'L3': [{'a': 1, 'b': 2}, {'c': 1, 'd': 2}]}}}
for item in flatten(data):
print(*item)
if __name__ == '__main__':
main()
输出:
L1 L2 L3 a 1 b 2
L1 L2 L3 c 1 d 2
评论
0赞
juanpa.arrivillaga
8/19/2023
为什么?这更快吗?
1赞
Alain T.
8/19/2023
#2
如果您关心的是嵌套循环的性能,您可能需要考虑为数据结构使用不同的模型,因为无论您如何处理嵌套,都会发生某种形式的嵌套。
如果问题出在不同的级别数量上,那么递归可能是你最好的选择(尽管它会比嵌套循环慢)。
下面是一个递归生成器,它将输出每一行,而无需创建结构的完整(扁平化)副本:
def flatItems(d,path=[]):
if isinstance(d,list):
for k,v in enumerate(d,1):
yield from flatItems(v,path+[k])
elif isinstance(d,dict):
for k,v in d.items():
yield from flatItems(v,path+[k])
else:
yield path + [d]
输出:
data = {'L1': {'L2': {'L3': [{'a': 1, 'b': 2}, {'c': 1, 'd': 2}]}}}
print(*flatItems(data),sep="\n")
['L1', 'L2', 'L3', 1, 'a', 1]
['L1', 'L2', 'L3', 1, 'b', 2]
['L1', 'L2', 'L3', 2, 'c', 1]
['L1', 'L2', 'L3', 2, 'd', 2]
请注意,根据您的示例,我对列表使用了基于 1 的索引。Python 的列表索引是从零开始的,您可能也想重新审视一下。
评论
[‘a’: 1, ‘b’: 2]
无效。 语法只允许在字典中使用,而不允许在列表中使用。key: value
itertools