将列表分成大致相等长度的N个部分

244 投票
37 回答
406476 浏览
提问于 2025-04-15 18:25

如何把一个列表分成大致相等的几部分呢?比如说,如果这个列表有7个元素,分成2部分的话,我们希望一部分有3个元素,另一部分有4个元素。

我想找一个像even_split(L, n)这样的函数,它可以把L分成n个部分。

def chunks(L, n):
    """ Yield successive n-sized chunks from L.
    """
    for i in range(0, len(L), n):
        yield L[i:i+n]

上面的代码会得到3个元素的块,而不是3个块。我可以简单地转置(遍历这个列表,取每一列的第一个元素作为第一部分,然后取第二个元素放入第二部分,依此类推),但这样会打乱元素的顺序。

37 个回答

281

这就是numpy.array_split的存在意义:

>>> import numpy as np
>>> print(*np.array_split(range(10), 3))
[0 1 2 3] [4 5 6] [7 8 9]
>>> print(*np.array_split(range(10), 4))
[0 1 2] [3 4 5] [6 7] [8 9]
>>> print(*np.array_split(range(10), 5))
[0 1] [2 3] [4 5] [6 7] [8 9]

*感谢Zero Piraeus在6号房间的贡献

336

你可以把它写得很简单,像一个列表生成器一样:

def split(a, n):
    k, m = divmod(len(a), n)
    return (a[i*k+min(i, m):(i+1)*k+min(i+1, m)] for i in range(n))

举个例子:

>>> list(split(range(11), 3))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10]]
78

这段代码有问题,因为它会出现四舍五入错误。不要使用它!!!

assert len(chunkIt([1,2,3], 10)) == 10  # fails

这里有一个可能有效的代码:

def chunkIt(seq, num):
    avg = len(seq) / float(num)
    out = []
    last = 0.0

    while last < len(seq):
        out.append(seq[int(last):int(last + avg)])
        last += avg

    return out

测试:

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

撰写回答