关于python:创建子列表

Creating sublists

本问题已经有最佳答案,请猛点这里访问。

与列表扁平化相反。

给定一个列表和一个长度n返回一个长度n子列表的列表。

1
2
3
4
5
6
7
def sublist(lst, n):
    sub=[] ; result=[]
    for i in lst:
        sub+=[i]
        if len(sub)==n: result+=[sub] ; sub=[]
    if sub: result+=[sub]
    return result

一个例子:

如果列表是:

1
[1,2,3,4,5,6,7,8]

n是:

1
3

返回:

1
[[1, 2, 3], [4, 5, 6], [7, 8]]

有更雄辩/简洁的方式吗?

除此之外,将列表附加到列表时首选的内容(在上面的上下文中):

1
list1+=[list2]

或:

1
list1.append(list2)

考虑到这一点(根据SummerFeild的"Python3编程"),它们是相同的?

谢谢。


这样的列表列表可以使用列表理解来构建:

1
2
3
In [17]: seq=[1,2,3,4,5,6,7,8]
In [18]: [seq[i:i+3] for i in range(0,len(seq),3)]
Out[18]: [[1, 2, 3], [4, 5, 6], [7, 8]]

还有Grouper成语:

1
2
3
In [19]: import itertools
In [20]: list(itertools.izip_longest(*[iter(seq)]*3))
Out[20]: [(1, 2, 3), (4, 5, 6), (7, 8, None)]

但请注意,缺少的元素用值none填充。Izip_longst也可以接受fillvalue参数,如果不需要其他参数。

list1+=[list2]——这次注意括号——相当于list1.append(list2)。我写代码的最高优先权是可读性,不是速度。因为这个原因,我会和list1.append(list2)一起去。不过,可读性是主观的,可能很大程度上受您熟悉的习惯用法的影响。

令人高兴的是,在这种情况下,可读性和速度似乎是一致的:

1
2
3
4
5
In [41]: %timeit list1=[1,2,3]; list1.append(list2)
1000000 loops, best of 3: 612 ns per loop

In [42]: %timeit list1=[1,2,3]; list1+=[list2]
1000000 loops, best of 3: 847 ns per loop


以下几点怎么样(你的单子是x)

1
 [x[i:i+3] for i in range(0, len(x), 3)]

这对于n!=3来说是微不足道的概括。

至于你的第二个问题,它们是等价的,所以我认为这是一个风格问题。但是,一定要确保你不会混淆appendextend


此函数可以采用任何类型的iterable(不仅是已知长度的序列):

1
2
3
4
5
6
7
8
9
import itertools

def grouper(n, it):
   "grouper(3, 'ABCDEFG') --> ABC DEF G"
    it = iter(it)
    return iter(lambda: list(itertools.islice(it, n)), [])

print(list(grouper(3, [1,2,3,4,5,6,7,8,9,10])))
# [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]


你听说过boltons吗?

Boltons is a set of pure-Python utilities in the same spirit as — and yet conspicuously missing from — the the standard library

它有你想要的,内置的,叫做chunked

1
2
3
from boltons import iterutils

iterutils.chunked([1,2,3,4,5,6,7,8], 3)

输出:

1
[[1, 2, 3], [4, 5, 6], [7, 8]]

boltons中,更吸引人的是它使用chunked作为迭代器,称为chunked_iter,所以您不需要将整个东西存储在内存中。整洁,对吧?


我认为这个split函数可以完成您想要的工作(尽管它与任何迭代器一起工作,而不仅仅是列表):

1
2
3
4
5
6
7
8
9
10
11
12
13
from itertools import islice

def take(n, it):
   "Return first n items of the iterable as a list"
    return list(islice(it, n))

def split(it, size):
    it = iter(it)
    size = int(size)
    ret = take(size, it)
    while ret:
        yield ret
        ret = take(size, it)

编辑:关于你的助手,我总是使用list.append(blah),因为我觉得它更惯用,但我相信它们在功能上是等价的。


对于某些特定的情况,使用numpy包可能很有用。在此包中,您有一个重塑例程:

1
2
3
import numpy as np
x = np.array([1,2,3,4,5,6])
np.reshape(x, (-1,3))

但是,如果不是n的倍数,这个解决方案不会填充您的列表。


我知道,这看起来像个脑残,但很有效:

1
2
3
4
5
6
7
8
>>> a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
>>> n = 3
>>> [i for j in [[a[t:t+n] for x in a[:1:t+1] if (t%n)==False] for t in range(len(a))] for i in j]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]

>>> n = 4
>>> [i for j in [[a[t:t+n] for x in a[:1:t+1] if (t%n)==False] for t in range(len(a))] for i in j]
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]