创建子列表

30 投票
7 回答
81274 浏览
提问于 2025-04-16 08:51

这是列表展开的反向操作。

给定一个列表和一个长度 n,返回一个包含长度为 n 的子列表的列表。

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,2,3,4,5,6,7,8]

而 n 是:

3

那么返回:

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

有没有更简洁的方法呢?

另外,在上面的上下文中,向列表中添加列表时,哪种方式更好:

list1+=[list2]

还是:

list1.append(list2)

考虑到(根据 Summerfeild 的《Python 3 编程》)它们是一样的?

谢谢。

7 个回答

10

你听说过 boltons 吗?

Boltons 是一组纯Python的工具,跟标准库里的东西有点像,但又有些缺失。

它里面有你想要的功能,叫做 chunked

from boltons import iterutils

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

输出:

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

而在 boltons 中更吸引人的是,它把 chunked 作为一个迭代器,叫做 chunked_iter,这样你就不需要把所有东西都存到内存里。是不是很不错?

11

下面这个怎么样(这里的 x 是你的列表):

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

这个对于 n!=3 来说也是很简单的。

至于你的第二个问题,它们是等价的,所以我觉得这主要是风格问题。不过,要确保你不要把 appendextend 搞混了

33

这样的列表可以通过一种叫做列表推导式来创建:

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

还有一种叫做分组习惯用法

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填充。如果你想用其他值而不是None,可以使用izip_longest,它可以接受一个fillvalue参数。


list1+=[list2] -- 这次注意到括号 -- 和list1.append(list2)是一样的。我写代码时最看重的是可读性,而不是速度。出于这个原因,我会选择list1.append(list2)。不过,可读性是主观的,可能会受到你熟悉的习惯用法的影响。

幸运的是,在这种情况下,可读性和速度似乎是相辅相成的:

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

撰写回答