Python 平铺序列,有时压缩后的数据需要平铺成一维序列,例如输入文件的结构可能如下所示:
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
...
可以用(line.split() for line in file)
生成一个序列,序列的每个元素是文件中一行数据构成的十元组。
得到的数据结构如下所示:
>>> blocked = list(line.split() for line in file)
>>> blocked
[['2', '3', '5', '7', '11', '13', '17', '19', '23', '29'], ['31', '37',
'41', '43', '47', '53', '59', '61', '67', '71'], ['179', '181', '191',
'193', '197', '199', '211', '223', '227', '229']]
但这并不是我们想要的最终结果,我们希望得到的结构是一维序列,但实际输入的每个元素都是十元组。每次拆解一个这样的元组则太过麻烦。
平铺这类数据结构,可以使用如下所示的双层生成器表达式:
>>> (x for line in blocked for x in line)
<generator object <genexpr> at 0x101cead70>
>>> list(_)
['2', '3', '5', '7', '11', '13', '17', '19', '23', '29', '31',
'37', '41', '43', '47', '53', '59', '61', '67', '71',
... ]
第一个for
从句从blocked
列表中解析出对象,每个对象是一个长度为10的列表,赋给line
变量,第二个for
从句从line
变量中解析出字符串,赋给x
变量,包含最终结果的生成器保存在x
变量中。
改写成如下形式更易于理解:
def flatten(data: Iterable[Iterable[Any]]) -> Iterable[Any]:
for line in data:
for x in line:
yield x
改写后可以看到生成器表达式的工作方式:外层for
从句(for line in data
)遍历输入数据中的每个十元组,内层for
从句(for x in line
)遍历外层语句中的每个元素。
这样双层序列复合型结构就转换成了单层序列。它能够将任何嵌套的双层可迭代对象转换为单层可迭代对象,例如双层列表、列表-集合组合结构等。