将n长度的列表分割成k长度的块的简单方法,当n % k > 0时?

12 投票
4 回答
735 浏览
提问于 2025-04-16 23:15

在Python中,如果一个列表的长度是另一个数字的倍数,分割这个列表成固定大小的小块是很简单的。比如说,如果你有一个长度为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个对同一个迭代器的引用的列表,这个迭代器是通过 iter(x) 得到的。然后 zip 会通过每次调用这k个迭代器的副本来生成每一块。前面的 * 是必须的,因为 zip 需要接收“分开的”迭代器,而不是一个列表。

我觉得这个方法的主要缺点是,当n不是k的倍数时,也就是 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) 这个方法?”但我觉得这个标题会让很多读者感到困惑。

我发现,把一个列表分成均匀大小的小块是多么简单,而去掉多余的填充却是相对困难的,尽管这两个问题看起来复杂度差不多。

4 个回答

3
sentinal = object()
split = ( 
    (v for v in r if v is not sentinal) for r in
    izip_longest(*[iter(x)]*n, fillvalue=sentinal))

当然,更好的做法是调用一个函数,因为这样比其他任何做同样事情的方法都更容易理解。

3

来自IPython的源代码:

def chop(seq,size):
    """Chop a sequence into chunks of the given size."""
    chunk = lambda i: seq[i:i+size]
    return map(chunk,xrange(0,len(seq),size))

如果这个序列不能被chunk整除,那么最后返回的列表里的元素会少于chunk的数量。简单来说,就是最后一部分会少一些,但它不会抱怨。

>>> chop(range(12),3)
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
>>> chop(range(12),4)
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
>>> chop(range(12),5)
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11]]
>>> chop(range(12),6)
[[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
15

在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这些问题可能是因为我们没有正确理解某些概念或者没有按照正确的方式来写代码。

当你在编写代码时,确保你理解每一行代码的作用。如果有不明白的地方,可以查阅相关的资料或者请教其他人。记住,编程是一个不断学习和实践的过程,不要害怕犯错,因为每次错误都是一次学习的机会。

另外,保持代码的整洁和可读性也很重要。这样不仅方便自己以后查看,也能让其他人更容易理解你的代码。

总之,编程需要耐心和细心,遇到问题时不要急躁,慢慢分析,找到解决办法。

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

撰写回答