2010-12-21 90 views
16

列表扁平化的反面。创建子列表

给定一个列表和长度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编程' ) 他们是一样的?

谢谢。

回答

15

这样的清单列表可以使用来构建一个list comprehension

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 idiom

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_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 
+0

感谢unutbu,不得不笑笑,这是使用列表理解的琐碎。强调我需要研究它们。关于+ = vs追加,我明白不同,注意到我比较了list1 + = [list2]到list1.append(list2),而不是list1 + = list2和list1.append(list2)。谢谢伟大的回答/讨论。 – 2010-12-21 17:10:17

+0

@Michael Puckett:哎呀,我误解了你的问题的第二部分。编辑... – unutbu 2010-12-21 17:27:02

1

我认为这个分流的功能做了你在找什么(尽管它可以与任何迭代器,而不是仅仅列出):

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) 

编辑:关于你的asside,我总是用list.append(废话),因为它对我来说更加习惯,但我相信它们在功能上是等同的。

+2

django的东西看起来并不需要 – 2010-12-21 16:49:10

+0

@Xavier烨,我已经删除它(我最初使用这个作为Django模板过滤器) – 2010-12-21 16:51:33

+0

谢谢加布里埃尔。 – 2010-12-21 17:37:18

6

如何以下(其中x是你的列表):

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

这是微不足道的概括为n!=3

至于你的第二个问题,它们是相同的,所以我认为这是一个风格问题。但是,确保你不是confusing append with extend

5

此功能可以采取任何一种可迭代的(不仅是已知长度的序列):

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

我知道,它看起来像一个brainfuck,但作品:

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

对于一些在特定的情况下,使用numpy包可能会很有用。在这个包你有reshape例行:

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

然而,这种解决方案将不会垫您的列表,如果它不是n的乘法。

2

您是否听说过boltons

Boltons是本着同样的精神作为一套纯Python实用程序 - 然而从明显缺失 - 的标准库

它拥有你想要的,内置的,所谓的​​

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,所以你并不需要保存在内存中的整个事情。整洁,对吧?