2010-02-09 161 views
22

什么是将列表分片为任意长度子列表的切片子列表部分的列表的最简单和合理有效的方式是什么?将列表切分成子列表列表

例如,如果我们的源列表为:

input = [1, 2, 3, 4, 5, 6, 7, 8, 9, ... ] 

而且我们的子列表长度为3,那么我们追求:

output = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ... ] 

同样,如果我们的子列表的长度是4,然后我们追求:

output = [ [1, 2, 3, 4], [5, 6, 7, 8], ... ] 
+2

@詹姆斯:你的加入是绝对没有关联的。 – SilentGhost 2010-02-09 19:13:24

+1

您可能对此问题的讨论感兴趣(http://stackoverflow.com/questions/2095637) – telliott99 2010-02-09 20:44:45

+0

您可以使用numpy的array_split函数,例如'np.array_split(np.array(data),20)'来分割分成20个几乎相同大小的块。要确保块的大小完全相同,请使用'np.split'。 – AlexG 2016-11-20 04:34:44

回答

64
[input[i:i+n] for i in range(0, len(input), n)]  # use xrange in py2k 

其中n是块的长度。

既然你没有定义什么可能发生在新列表的最后一个元素时input元素的数量不整除n,我认为这并不重要:这个你会得到最后一个元素例如,如果n等于7,则等于2。

14

itertools模块的文档包含以下recipe

import itertools 

def grouper(n, iterable, fillvalue=None): 
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" 
    args = [iter(iterable)] * n 
    return itertools.izip_longest(fillvalue=fillvalue, *args) 

该函数返回所希望的长度的元组的一个迭代:

>>> list(grouper(2, [1,2,3,4,5,6,7])) 
[(1, 2), (3, 4), (5, 6), (7, None)] 
+0

虽然这与任何迭代器一起工作,但当应用于给定任务时,它看起来不像我的代码那样高效(至少在我的测试中)。 – SilentGhost 2010-02-09 19:12:09

+3

@SilentGhost,过早优化? – 2010-02-09 19:15:42

+1

@Mike:我请你原谅? – SilentGhost 2010-02-09 19:16:50

0

我喜欢SilentGhost的溶液。

我的解决方案使用功能编程在python:

group = lambda t, n: zip(*[t[i::n] for i in range(n)]) 
group([1, 2, 3, 4], 2) 

给出:

[(1, 2), (3, 4)] 

这假定输入列表的大小是由基团尺寸整除。如果不是,则不包含未配对的元素。

+0

你的第二个例子仅限于python-2.x。在py3k中'map'不能把'None'作为第一个参数。 – SilentGhost 2010-02-09 19:51:44

+0

@SilentGhost:你说的对,我正在删除它。 – MKTech 2010-02-09 22:45:59

7

一个真正Python的变种(蟒蛇3):

list(zip(*(iter([1,2,3,4,5,6,7,8,9]),)*3)) 

列表迭代器创建,变成了具备3元组相同的迭代器,然后解压到拉链,浇铸再次列出。通过zip从每个迭代器中提取一个值,但由于只有一个迭代器对象,所以全部三个内部计数器全局增加。

+2

这个解决方案非常棒,但是如果我不得不考虑Python的禅宗,我会说它不是非常“pythonic”:P – AkiRoss 2015-04-02 10:25:53

+1

没错,它是一种非pythonic pythonic解决方案;-) – CoDEmanX 2015-04-03 20:26:56

+0

如果mod的len列表不是0! – 2018-01-18 10:59:26