python - 当 n % k > 0 时,将 n 长列表分成 k 长 block 的简单习语?

标签 python python-itertools map-function

在 Python 中,如果 n 的倍数,很容易将 n 长的列表分成 k 大小的 block >k(IOW,n % k == 0)。这是我最喜欢的方法(直接来自 docs ):

>>> 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相同迭代器 的引用列表,作为返回通过 iter(x)。然后 zip 通过恰好调用迭代器的每个 k 副本来生成每个 block 。* [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)]

至少,这里保留了剩余的条目,但最后一个 block 用 None 填充。如果只是想要不同的填充值,那么 itertools.izip_longest解决问题。

但假设所需的解决方案是最后一个 block 未填充的解决方案,即

[(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11), (12, 13, 14)]

有没有一种简单的方法来修改 map(None, *[iter(x)]*k) 习惯用法来产生这个结果?

(诚然,通过编写一个函数来解决这个问题并不难(例如,参见对 How do you split a list into evenly sized chunks?What is the most "pythonic" way to iterate over a list in chunks? 的许多精彩回复)。因此,这个问题更准确的标题是“如何挽救 map(None, *[iter(x)]*k) 成语?”,但我认为这会让很多读者感到困惑。)

令我震惊的是将列表分成大小均匀的 block 是多么容易,而(相比之下!)去除不需要的填充是多么困难,即使这两个问题似乎具有相当的复杂性。

最佳答案

[x[i:i+k] for i in range(0,n,k)]

关于python - 当 n % k > 0 时,将 n 长列表分成 k 长 block 的简单习语?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7005323/

相关文章:

python - 不是 Python 中的 None 测试

Python `tempfile.gettempdir()` 不尊重 TMPDIR

python - 在此 itertools 配方中定义 seen_add = seen.add 有什么意义?

python - 协程上的 itertools.tee?

python - 对 map 对象进行成员资格测试时出现意外结果

Java - Spark SQL DataFrame 映射函数不工作

Python:过滤器(函数,序列)和映射(函数,序列)之间的区别

python - snakemake 临时目录

python - 生成所有一定次数的多项式项

python - groupby 并将列堆叠到单个列中