将列表切片成子列表的列表

42
什么是将列表切片为任意长度的子列表的最简单且合理高效的方法?例如,如果我们的源列表如下:
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], ... ]

1
您可能会对这个问题的讨论感兴趣(https://dev59.com/j0vSa4cB1Zd3GeqPeGz9) - telliott99
你可以使用numpy的array_split函数,例如np.array_split(np.array(data), 20)将数据分成20个大小相近的块。如果要确保块的大小完全相等,请使用np.split - Alex
4个回答

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

其中n表示一个块的长度。

由于您没有定义当输入列表中的元素数量不能被n整除时新列表的最后一个元素可能发生的情况,因此我假设这没有关系:例如,当n等于7时,您将得到最后一个元素等于2。


17

Python的 itertools 模块文档包含以下配方

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

1
虽然这个方法适用于任何可迭代对象,但在我的测试中,与我编写的代码相比,在执行给定任务时似乎不太高效。 - SilentGhost
3
@SilentGhost,过早优化? - Mike Graham

9

一个真正的pythonic变体(Python 3):

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

创建一个列表迭代器,将其转换为包含3个相同迭代器的元组,然后解包为zip并再次转换为列表。zip从每个迭代器中取出一个值,但由于只有一个迭代器对象,所有三个迭代器的内部计数器都会全局增加。


6
这个解决方案很棒,但如果考虑Python的"Python风格"(zen of python),我会说它并不十分符合 :P - AkiRoss
1
没错,这是一种非Python风格的Python解决方案;-) - CodeManX
1
如果列表长度的模不为0,则无法工作! - Denny Weinberg
不起作用! - Jorge Machado

1

我喜欢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)]

这假设输入列表的大小能够被组大小整除,否则未成对的元素将不会被包括。


你的第二个例子仅适用于Python 2.x。在Py3k中,map不能将None作为第一个参数。 - SilentGhost
@SilentGhost:你是对的,我会把它移除掉。 - MKTech

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接