Python将列表分割成n个块
我知道这个问题已经被讨论过很多次,但我的需求有点不同。
我有一个列表,比如说:range(1, 26)
。我想把这个列表分成固定数量的部分,假设这个数量是 n
,也就是 6。
>>> x
[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]
>>> l = [ x [i:i + 6] for i in range(0, len(x), 6) ]
>>> l
[[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]]
如你所见,我没有得到 6 个部分(六个子列表,每个子列表包含原列表的元素)。我想知道怎么才能把一个列表分成正好 n
个部分,这些部分可以是相等的,也可以是不相等的。
22 个回答
8
我想出了以下解决方案:
l = [x[i::n] for i in range(n)]
举个例子:
n = 6
x = list(range(26))
l = [x[i::n] for i in range(n)]
print(l)
输出结果:
[[0, 6, 12, 18, 24], [1, 7, 13, 19, 25], [2, 8, 14, 20], [3, 9, 15, 21], [4, 10, 16, 22], [5, 11, 17, 23]]
你可以看到,输出结果由 n
个部分组成,这些部分大致上有相同数量的元素。
这个是怎么实现的呢?
关键在于使用列表切片的步长(就是两个分号后面的数字),并且要逐步增加切片的起始位置。首先,从第一个元素开始,每隔 n
个取一个,然后从第二个元素开始,每隔 n
个取一个,依此类推。这样就完成了任务。
14
more_itertools.divide
是解决这个问题的一种方法:
import more_itertools as mit
iterable = range(1, 26)
[list(c) for c in mit.divide(6, iterable)]
输出结果
[[ 1, 2, 3, 4, 5], # remaining item
[ 6, 7, 8, 9],
[10, 11, 12, 13],
[14, 15, 16, 17],
[18, 19, 20, 21],
[22, 23, 24, 25]]
如图所示,如果可迭代对象不能被均匀分割,剩下的项目会从第一个部分分配到最后一个部分。
想了解更多关于 more_itertools
库的信息,可以点击这里。
37
如果顺序不重要:
def chunker_list(seq, size):
return (seq[i::size] for i in range(size))
print(list(chunker_list([1, 2, 3, 4, 5], 2)))
>>> [[1, 3, 5], [2, 4]]
print(list(chunker_list([1, 2, 3, 4, 5], 3)))
>>> [[1, 4], [2, 5], [3]]
print(list(chunker_list([1, 2, 3, 4, 5], 4)))
>>> [[1, 5], [2], [3], [4]]
print(list(chunker_list([1, 2, 3, 4, 5], 5)))
>>> [[1], [2], [3], [4], [5]]
print(list(chunker_list([1, 2, 3, 4, 5], 6)))
>>> [[1], [2], [3], [4], [5], []]
51
下面的解决方案有很多优点:
- 使用生成器来返回结果。
- 不需要导入任何库。
- 列表的大小是均衡的(比如把一个长度为17的列表分成5个列表时,不会出现4个列表大小为4,1个列表大小为1的情况)。
def chunks(l, n):
"""Yield n number of striped chunks from l."""
for i in range(0, n):
yield l[i::n]
上面的代码对于 l = range(16)
和 n = 6
会产生以下输出:
[0, 6, 12]
[1, 7, 13]
[2, 8, 14]
[3, 9, 15]
[4, 10]
[5, 11]
如果你需要的分块是连续的,而不是交错的,可以使用这个:
def chunks(l, n):
"""Yield n number of sequential chunks from l."""
d, r = divmod(len(l), n)
for i in range(n):
si = (d+1)*(i if i < r else r) + d*(0 if i < r else i - r)
yield l[si:si+(d+1 if i < r else d)]
对于 l = range(16)
和 n = 6
,会产生:
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9, 10, 11]
[12, 13]
[14, 15]
想了解生成器的更多优点,可以查看 这个stackoverflow链接。
75
使用numpy
>>> import numpy
>>> x = range(25)
>>> l = numpy.array_split(numpy.array(x),6)
或者
>>> import numpy
>>> x = numpy.arange(25)
>>> l = numpy.array_split(x,6);
你也可以用numpy.split这个方法,但如果长度不能被整除,它会报错。