创建子列表
这是列表展开的反向操作。
给定一个列表和一个长度 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
来说也是很简单的。
至于你的第二个问题,它们是等价的,所以我觉得这主要是风格问题。不过,要确保你不要把 append
和 extend
搞混了。
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