将列表拆分为大约相等长度的N个部分
将列表拆分为的最佳方式大致相等的部分是?例如,如果列表包含7个元素并将其分成2部分,则我们希望在一个部分中获得3个元素,而另一个元素应该包含4个元素。将列表拆分为大约相等长度的N个部分
我在寻找类似even_split(L, n)
的东西,将L
分解为n
部件。
def chunks(L, n):
""" Yield successive n-sized chunks from L.
"""
for i in xrange(0, len(L), n):
yield L[i:i+n]
上面的代码给出了3个块,而不是3个块。我可以简单地转置(遍历这个并获取每列的第一个元素,调用第一部分,然后把第二部分放在第二部分等),但是这会破坏项目的顺序。
这里有一个可以工作:
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]]
更改代码以获得n
块,而不是n
大块:
def chunks(l, n):
""" Yield n successive chunks from l.
"""
newn = int(len(l)/n)
for i in xrange(0, n-1):
yield l[i*newn:i*newn+newn]
yield l[n*newn-newn:]
l = range(56)
three_chunks = chunks (l, 3)
print three_chunks.next()
print three_chunks.next()
print three_chunks.next()
这给:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
[18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]
[36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]
这将为最终的组分配额外的元素,这是不完美的,但在您的“大致N个相等部分”的规范中:-)因此,我的意思是56个元素会更好(19,19, 18),而这给(18,18,20)。
你可以用下面的代码更平衡输出:
#!/usr/bin/python
def chunks(l, n):
""" Yield n successive chunks from l.
"""
newn = int(1.0 * len(l)/n + 0.5)
for i in xrange(0, n-1):
yield l[i*newn:i*newn+newn]
yield l[n*newn-newn:]
l = range(56)
three_chunks = chunks (l, 3)
print three_chunks.next()
print three_chunks.next()
print three_chunks.next()
,输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
[19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37]
[38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]
这给了我一个奇怪的结果。对于p大块(范围(54),3):打印len(p)返回18,18,51 ... – user248237dfsf 2010-01-25 03:36:16
固定,这是最终收益率。 – paxdiablo 2010-01-25 03:37:38
另请参见在[链接]上的一个孤独(http://stackoverflow.com/questions/17749743/python-split-a-list-into-x-number-of-chunks?lq=1) – 2013-07-19 16:14:20
这是一个增加None
使列表长度相等
>>> from itertools import izip_longest
>>> def chunks(l, n):
""" Yield n successive chunks from l. Pads extra spaces with None
"""
return list(zip(*izip_longest(*[iter(l)]*n)))
>>> l=range(54)
>>> chunks(l,3)
[(0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51), (1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52), (2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53)]
>>> chunks(l,4)
[(0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52), (1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53), (2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, None), (3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, None)]
>>> chunks(l,5)
[(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50), (1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51), (2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52), (3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53), (4, 9, 14, 19, 24, 29, 34, 39, 44, 49, None)]
你可以简单地写成列表生成器:
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 xrange(n))
例子:
>>> list(split(range(11), 3))
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10]]
只要你不想做傻事像连续大块:
>>> def chunkify(lst,n):
... return [lst[i::n] for i in xrange(n)]
...
>>> chunkify(range(13), 3)
[[0, 3, 6, 9, 12], [1, 4, 7, 10], [2, 5, 8, 11]]
看一看numpy.split:
>>> a = numpy.array([1,2,3,4])
>>> numpy.split(a, 2)
[array([1, 2]), array([3, 4])]
另一个方式会是这样的,这里的想法是你se石斑鱼,但摆脱None
。在这种情况下,我们将拥有由列表第一部分中的元素组成的所有'small_parts',以及列表后部分中的'large_parts'。 “较大部分”的长度是len(small_parts)+ 1.我们需要将x看作两个不同的子部分。
from itertools import izip_longest
import numpy as np
def grouper(n, iterable, fillvalue=None): # This is grouper from itertools
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
def another_chunk(x,num):
extra_ele = len(x)%num #gives number of parts that will have an extra element
small_part = int(np.floor(len(x)/num)) #gives number of elements in a small part
new_x = list(grouper(small_part,x[:small_part*(num-extra_ele)]))
new_x.extend(list(grouper(small_part+1,x[small_part*(num-extra_ele):])))
return new_x
我把它设置了退货的方式元组的列表:
>>> x = range(14)
>>> another_chunk(x,3)
[(0, 1, 2, 3), (4, 5, 6, 7, 8), (9, 10, 11, 12, 13)]
>>> another_chunk(x,4)
[(0, 1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13)]
>>> another_chunk(x,5)
[(0, 1), (2, 3, 4), (5, 6, 7), (8, 9, 10), (11, 12, 13)]
>>>
下面是均匀地分布“剩余”的元素所有块中,一次一个,直到有另一种变体没有剩下。在这个实现中,更大的块在过程开始时发生。
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]
同为job's的答案,但考虑到与列表大小大于chuncks的数量少。
def chunkify(lst,n):
[ lst[i::n] for i in xrange(n if n < len(lst) else len(lst)) ]
如果n(块的数量)是7和LST(列表划分)为[1,2,3]的块是[[0],[1],[2]]代替[[0],[1],[2],[],[],[],[]]
这是我的解决方案:
def chunks(l, amount):
if amount < 1:
raise ValueError('amount must be positive integer')
chunk_len = len(l) // amount
leap_parts = len(l) % amount
remainder = amount // 2 # make it symmetrical
i = 0
while i < len(l):
remainder += leap_parts
end_index = i + chunk_len
if remainder >= amount:
remainder -= amount
end_index += 1
yield l[i:end_index]
i = end_index
可生产
>>> list(chunks([1, 2, 3, 4, 5, 6, 7], 3))
[[1, 2], [3, 4, 5], [6, 7]]
这是我用过的。完美!谢谢 – brunetton 2017-12-26 21:54:41
您也可以使用:
split=lambda x,n: x if not x else [x[:n]]+[split([] if not -(len(x)-n) else x[-(len(x)-n):],n)][0]
split([1,2,3,4,5,6,7,8,9],2)
[[1, 2], [3, 4], [5, 6], [7, 8], [9]]
使用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])]
使用列表理解:
def divide_list_to_chunks(list_, n):
return [list_[start::n] for start in range(n)]
这并没有解决甚至使所有块的问题。 – SuperBiasedMan 2015-11-14 15:25:44
如果分割n
元素融入大致k
块就可以使n % k
块1周的Elemen比其他块分配更多的元素。
下面的代码会给你的长度各块:
[(n // k) + (1 if i < (n % k) else 0) for i in range(k)]
例子:n=11, k=3
结果[4, 4, 3]
然后,您可以方便地计算出开始indizes各块:
[i * (n // k) + min(i, n % k) for i in range(k)]
例如:n=11, k=3
re sults在[0, 4, 8]
使用i+1
个块作为我们得到的名单l
与LEN n
的i
个块是
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)
结果[range(0, 4), range(4, 8), range(8, 11)]
舍入linspace并将其用作索引比amit12690提出的更容易。
function chunks=chunkit(array,num)
index = round(linspace(0,size(array,2),num+1));
chunks = cell(1,num);
for x = 1:num
chunks{x} = array(:,index(x)+1:index(x+1));
end
end
这是一个很好的Matlab回答... – 2016-08-15 19:55:22
这是numpy.array_split
的存在的理由 *:
>>> L
[0, 1, 2, 3, 4, 5, 6, 7]
>>> print(*np.array_split(L, 3))
[0 1 2] [3 4 5] [6 7]
>>> print(*np.array_split(range(10), 4))
[0 1 2] [3 4 5] [6 7] [8 9]
*信贷Zero Piraeus在6室
这应该是顶级答案 – bluesummers 2017-05-10 10:59:49
trèsbien mon cher! – VanillaSpinIce 2017-09-16 21:46:46
这里有一台发电机,可以处理任何正(整)块数。如果块的数量大于输入列表长度,则某些块将为空。该算法在短块和长块之间交替而不是分离它们。
我还包括一些测试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
电话,但我觉得以前的版本更易读(和烘干机)。
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
这将通过单个表达做分割:
>>> myList = range(18)
>>> parts = 5
>>> [myList[(i*len(myList))//parts:((i+1)*len(myList))//parts] for i in range(parts)]
[[0, 1, 2], [3, 4, 5, 6], [7, 8, 9], [10, 11, 12, 13], [14, 15, 16, 17]]
在这个例子中的列表具有18的尺寸和被分成5份。部件的尺寸不超过一个元件。
我的解决方案,易于理解
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)]
你的榜样将不会为'''工作>>> chunkIt(range(8),6)'''=> '''[[0],[1],[2,3],[4],[5],[6],[7]]' '' – nopper 2013-10-07 16:01:57
@nopper,我添加了一个“if num == 1:”条件来处理这个边界情况。 – paulie4 2013-10-10 15:18:02
新访问者:**请不要使用或注释此代码**,它已损坏。例如'chunkIt(range(10),9)'应该返回9个部分,但不是。 – wim 2017-05-16 01:58:52