2010-12-21 110 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,所以你並不需要保存在內存中的整個事情。整潔,對吧?