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


当前回答

使用numpy实现。linspace方法。

只需指定要将数组分成的部分的数量。各部门的规模将几乎相同。

例子:

import numpy as np   
a=np.arange(10)
print "Input array:",a 
parts=3
i=np.linspace(np.min(a),np.max(a)+1,parts+1)
i=np.array(i,dtype='uint16') # Indices should be floats
split_arr=[]
for ind in range(i.size-1):
    split_arr.append(a[i[ind]:i[ind+1]]
print "Array split in to %d parts : "%(parts),split_arr

给:

Input array: [0 1 2 3 4 5 6 7 8 9]
Array split in to 3 parts :  [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8, 9])]

其他回答

如果你不介意顺序会改变,我建议你使用@job solution,否则,你可以使用这个:

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

    while last < len(seq):
        if len(seq) - (last + steps) < steps:
            until = len(seq)
            steps = len(seq) - last
        else:
            until = int(last + steps)
        out.append(seq[int(last): until])
        last += steps
return out

这里有一个生成器,可以处理任何正(整数)数量的块。如果块的数量大于输入列表的长度,一些块将为空。该算法在短块和长块之间交替,而不是将它们分开。

我还包含了一些用于测试ragged_chunks函数的代码。

''' Split a list into "ragged" chunks

    The size of each chunk is either the floor or ceiling of len(seq) / chunks

    chunks can be > len(seq), in which case there will be empty chunks

    Written by PM 2Ring 2017.03.30
'''

def ragged_chunks(seq, chunks):
    size = len(seq)
    start = 0
    for i in range(1, chunks + 1):
        stop = i * size // chunks
        yield seq[start:stop]
        start = stop

# test

def test_ragged_chunks(maxsize):
    for size in range(0, maxsize):
        seq = list(range(size))
        for chunks in range(1, size + 1):
            minwidth = size // chunks
            #ceiling division
            maxwidth = -(-size // chunks)
            a = list(ragged_chunks(seq, chunks))
            sizes = [len(u) for u in a]
            deltas = all(minwidth <= u <= maxwidth for u in sizes)
            assert all((sum(a, []) == seq, sum(sizes) == size, deltas))
    return True

if test_ragged_chunks(100):
    print('ok')

我们可以通过将乘法导出到range调用中来稍微提高效率,但我认为以前的版本更易于阅读(和dry)。

def ragged_chunks(seq, chunks):
    size = len(seq)
    start = 0
    for i in range(size, size * chunks + 1, size):
        stop = i // chunks
        yield seq[start:stop]
        start = stop
n = len(lst)
# p is the number of parts to be divided
x = int(n/p)

i = 0
j = x
lstt = []
while (i< len(lst) or j <len(lst)):
    lstt.append(lst[i:j])
    i+=x
    j+=x
print(lstt)

这是最简单的答案,如果已知列表分成相等的部分。

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

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]

你可以把它简单地写成一个列表生成器:

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