假设我有一个任意嵌套的列表,其中一些嵌套元素可以是生成器。例如:
nested_gens = [
[1, [2, [3, 4]]],
[2, (map(int, '123'))],
[3, (map(str, range(i+1)) for i in range(2))],
{'a': ({k: (float(i) for i in range(2))} for k in 'xyz')},
{'b': {'c': dict(zip(range(3), 'abc'))}}
]
如何递归地遍历此结构并使用所有生成器对象?
我想要的输出是:
[
[1, [2, [3, 4]]],
[2, [1, 2, 3]],
[3, [['0'], ['0', '1']]],
{'a': [{'x': [0.0, 1.0]}, {'y': [0.0, 1.0]}, {'z': [0.0, 1.0]}]},
{'b': {'c': {0: 'a', 1: 'b', 2: 'c'}}}
]
对于包含发电机的酸洗对象,可以普遍解决该问题。我找到的与TypeError: can't pickle generator objects
处理有关的所有答案都与嵌套生成器无关。
更新: 该解决方案应该能够处理任何类型的嵌套元素。
答案 0 :(得分:1)
一种方法是递归地遍历嵌套对象,然后将生成器转换为list
。
from inspect import isgenerator, isgeneratorfunction
def consume_all_generators(row):
if isinstance(row, str):
return row
elif isinstance(row, dict):
return {k: consume_all_generators(v) for k, v in row.items()}
output = []
try:
for val in row:
if isgenerator(val) or isgeneratorfunction(val):
output.append(list(consume_all_generators(val)))
else:
output.append(consume_all_generators(val))
return output
except TypeError:
return row
将其应用于问题中的示例:
print(consume_all_generators(nested_gens))
#[[1, [2, [3, 4]]],
# [2, [1, 2, 3]],
# [3, [['0'], ['0', '1']]],
# {'a': [{'x': [0.0, 1.0]}, {'y': [0.0, 1.0]}, {'z': [0.0, 1.0]}]},
# {'b': {'c': {0: 'a', 1: 'b', 2: 'c'}}}]
答案 1 :(得分:0)
对于不导入的解决方案,您还可以递归使用列表推导:
def _test(d):
if isinstance(d, str):
return d
try:
_l = [i for i in d]
return [_test(i) for i in _l] if not isinstance(d, dict) else {a:_test(b) for a, b in d.items()}
except:
return d
nested_gens = [
[1, [2, [3, 4]]],
[2, (map(int, '123'))],
[3, (map(str, range(i+1)) for i in range(2))],
{'a': ({k: (float(i) for i in range(2))} for k in 'xyz')},
{'b': {'c': dict(zip(range(3), 'abc'))}}
]
print(_test(nested_gens))
输出:
[[1, [2, [3, 4]]], [2, [1, 2, 3]], [3, [['0'], ['0', '1']]], {'a': [{'x': [0.0, 1.0]}, {'y': [0.0, 1.0]}, {'z': [0.0, 1.0]}]}, {'b': {'c': {0: 'a', 1: 'b', 2: 'c'}}}]
答案 2 :(得分:0)
尝试一下
def consume(g):
if hasattr(g, '__iter__') and not isinstance(g, str):
if isinstance(g, tuple):
return (consume(e) for e in g)
elif isinstance(g, dict):
return { k: consume(v) for k,v in g.items()}
else:
return [consume(e) for e in g]
return g
nested_gens = [ [1, [2, [3, 4]]],
[2, (map(int, '123'))],
[3, (map(str, range(i+1)) for i in range(2))],
{'a': ({k: (float(i) for i in range(2))} for k in 'xyz')},
{'b': {'c': dict(zip(range(3), 'abc'))}} ]
print(consume(nested_gens))