摄影:产品经理
有这样一个列表套列表的数据结构:
a = [1, 2, [3, 4, [5, 6, 7], 8], 9, [10, 11]]
现在想把它变为:
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
遇到这种问题,肯定有很多人想到用递归和循环来实现:
def flat(deep_list, result): for element in deep_list: if isinstance(element, list): flat(element, result) else: result.append(element)
a = [1, 2, [3, 4, [5, 6, 7], 8], 9, [10, 11]] result = [] flat(a, result) print(result)
这样做确实能达到目的,但是需要把储存结果的列表作为参数不停递归传入。
实际上,如果使用生成器,这个问题就会变得简单很多:
def flat(deep_list): for element in deep_list: if isinstance(element, list): yield from flat(element) else: yield element
a = [1, 2, [3, 4, [5, 6, 7], 8], 9, [10, 11]] result = [x for x in flat(a)] print(result)
在这个解法里面,使用了 yield
和 yieldfrom
实现生成器,当我们直接对生成器进行迭代的时候,就得到了结果。
其中, yieldfrom
是从Python 3.3开始引入的写法:
yield from x # 等价于 for g in x: yield g
所以,当代码运行到
[x for x in flat(a)]
的时候,每一次循环都会进入到 flat
生成器里面。在 flat
里面,对传入的参数使用for循环进行迭代,如果拿到的元素不是列表,那么就直接抛出,送到上一层。如果当前已经是最上层了,那么就再一次抛出给外面的列表推导式。如果当前元素是列表,那么继续生成一个生成器,并对这个新的生成器进行迭代,并把每一个结果继续往上层抛出。
最终,每一个数字都会被一层一层往上抛出给列表推导式,从而获得需要的结果。