将清单大致等份的最佳方法是什么?例如,如果列表有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个块。我可以简单地转置(遍历这个,取每列的第一个元素,称之为第一部分,然后取第二个元素,把它放在第二部分,等等),但这破坏了项目的顺序。


当前回答

如果你把n个元素分成大约k个块,你可以让n % k个块1个元素比其他块大,以分配额外的元素。

下面的代码将给出块的长度:

[(n // k) + (1 if i < (n % k) else 0) for i in range(k)]

示例:n=11, k=3结果为[4,4,3]

然后你可以很容易地计算块的起始索引:

[i * (n // k) + min(i, n % k) for i in range(k)]

示例:n=11, k=3结果为[0,4,8]

使用第i+1块作为边界,我们得到列表l的第i块(len n)是

l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)]

作为最后一步,使用列表理解从所有块创建一个列表:

[l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)] for i in range(k)]

示例:n=11, k=3, l=range(n) results in [range(0,4), range(4,8), range(8,11)]

其他回答

它提供长度<= n, >= 0的块

def

 chunkify(lst, n):
    num_chunks = int(math.ceil(len(lst) / float(n))) if n < len(lst) else 1
    return [lst[n*i:n*(i+1)] for i in range(num_chunks)]

例如

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

我的解决方案,很容易理解

def split_list(lst, n):
    splitted = []
    for i in reversed(range(1, n + 1)):
        split_point = len(lst)//i
        splitted.append(lst[:split_point])
        lst = lst[split_point:]
    return splitted

这页上最短的一句话(我的女朋友写的)

def split(l, n):
    return [l[int(i*len(l)/n):int((i+1)*len(l)/n-1)] for i in range(n)]

这是另一种变体,它将“剩余”元素均匀地分布在所有块中,一次一个,直到一个都不剩。在这个实现中,较大的块出现在流程的开头。

def chunks(l, k):
  """ Yield k successive chunks from l."""
  if k < 1:
    yield []
    raise StopIteration
  n = len(l)
  avg = n/k
  remainders = n % k
  start, end = 0, avg
  while start < n:
    if remainders > 0:
      end = end + 1
      remainders = remainders - 1
    yield l[start:end]
    start, end = end, end+avg

例如,从14个元素的列表中生成4个块:

>>> list(chunks(range(14), 4))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10], [11, 12, 13]]
>>> map(len, list(chunks(range(14), 4)))
[4, 4, 3, 3]

如果你把n个元素分成大约k个块,你可以让n % k个块1个元素比其他块大,以分配额外的元素。

下面的代码将给出块的长度:

[(n // k) + (1 if i < (n % k) else 0) for i in range(k)]

示例:n=11, k=3结果为[4,4,3]

然后你可以很容易地计算块的起始索引:

[i * (n // k) + min(i, n % k) for i in range(k)]

示例:n=11, k=3结果为[0,4,8]

使用第i+1块作为边界,我们得到列表l的第i块(len n)是

l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)]

作为最后一步,使用列表理解从所有块创建一个列表:

[l[i * (n // k) + min(i, n % k):(i+1) * (n // k) + min(i+1, n % k)] for i in range(k)]

示例:n=11, k=3, l=range(n) results in [range(0,4), range(4,8), range(8,11)]

这就是numpy.array_split*使用d'être的原因:

>>> 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]

*贷方是6号房间的零比雷埃夫斯