我将在上一步的结果的基础上逐步解释解决方案。
要按索引对每个列表中的项目进行分组,itertools.zip_longest() 是这样做的工具:
>>> import itertools as it
>>> MISSING = object() # a sentinel
>>> lsts = [
[7, 23, 5, 2],
[3, 8, 1],
[99, 23, 9, 23, 74]
]
>>> it.zip_longest(*lsts, fillvalue=MISSING)
>>> list(_)
[(7, 3, 99), (23, 8, 23), (5, 1, 9), (2, <object object at 0x7f529e9b4260>, 23), (<object object at 0x7f529e9b4260>, <object object at 0x7f529e9b4260>, 74)]
这会在需要时使用 MISSING 填充值将列表元素分组为 n 元组,因为列表的长度可能不相等。
下一步是遍历每个 n 元组并在内部对其进行排序(同时跳过 MISSING 值)。内置函数sorted() 在这里派上用场:
>>> list(
sorted(x for x in ntuple if x is not MISSING)
for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
)
[[3, 7, 99], [8, 23, 23], [1, 5, 9], [2, 23], [74]]
最后一步是展平这个列表序列,我们将使用itertools.chain,from_iterable():
>>> list(it.chain.from_iterable(
sorted(x for x in ntuple if x is not MISSING)
for ntuple in it.zip_longest(*lsts, fillvalue=MISSING)
))
[3, 7, 99, 8, 23, 23, 1, 5, 9, 2, 23, 74]
chain.from_iterable() 的好处是它不会重复地将较小的列表连接到越来越长的最终列表中,从而提高效率。它也在 C 级别执行此操作,AFAIK。
值得注意的是,None 也可以用来代替 MISSING 哨兵,但我还使用 MISSING 来演示 fillvalue 的工作原理(例如,如果你想使用零或其他东西,如果你希望)。