在 Python 中,如果n是k (IOW, ) 的倍数,则很容易将n长的列表分成k大小的块。这是我最喜欢的方法(直接来自文档):n % k == 0
>>> k = 3
>>> n = 5 * k
>>> x = range(k * 5)
>>> zip(*[iter(x)] * k)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
(诀窍是[iter(x)] * k
产生一个对同一个迭代器的k引用的列表,由 . 返回。然后通过调用迭代器的每个k个副本恰好一次来生成每个块。之前是必要的,因为期望将其参数作为“单独" 迭代器,而不是它们的列表。)iter(x)
zip
*
[iter(x)] * k
zip
我看到这个习语的主要缺点是,当n不是k (IOW, n % k > 0
) 的倍数时,剩下的条目就被遗漏了;例如:
>>> zip(*[iter(x)] * (k + 1))
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
还有一种替代习语,它的类型稍长,在 时产生与上述相同的结果n % k == 0
,并且在 时具有更可接受的行为n % k > 0
:
>>> map(None, *[iter(x)] * k)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
>>> map(None, *[iter(x)] * (k + 1))
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14, None)]
至少,这里保留了剩余的条目,但最后一个块用None
. 如果一个人只是想要一个不同的填充值,那么就itertools.izip_longest
解决了这个问题。
但是假设所需的解决方案是最后一块未填充的解决方案,即
[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14)]
有没有一种简单的方法来修改map(None, *[iter(x)]*k)
成语来产生这个结果?
(当然,通过编写一个函数来解决这个问题并不难(例如,参见对如何将列表拆分为大小均匀的块?或什么是最“pythonic”的迭代分块列出?)。因此,这个问题的更准确的标题是“如何挽救map(None, *[iter(x)]*k)
成语?”,但我认为这会让很多读者感到困惑。)
我惊讶于将列表分成大小均匀的块是多么容易,以及摆脱不需要的填充是多么困难(相比之下!),即使这两个问题看起来具有相当的复杂性。