2015-01-04 45 views
0

我有一個列表,如[[1,2], [3,4], [5,6], [7,8], [9,10]]。我想得到[1,2,3,4,5,6,7,8,9,10]扁平列表如果子列表長度相同

This question給出了一些非常好的平坦化列表的選項。給出的答案適用於變長子列表。儘管如此,我知道每個子列表具有相同的長度(特別是長度2)。

我想知道是否有可能利用均勻的子列表長度來改善我在鏈接到的問題中給出的答案。特別是,有沒有什麼比扁平化這個列表更好的比[item for sublist in l for item in sublist]

編輯:作'更好',我的意思是一個很長的名單更快。

編輯:

有一件事我沒有提到 - 我不關心扁平列表的順序(但我關心的多重度)

import timeit 
import itertools 
def f0(): 
    l=[[1,2]]*99 
    [item for sublist in l for item in sublist] 
def f1(): 
    l=[[1,2]]*99 
    list(itertools.chain.from_iterable(l)) 
def f2(): 
    l = [[1,2]]*99 
    z = map(list,zip(*l)) 
    z[0].extend(z[1]) 

print timeit.timeit("f0()", setup="from __main__ import f0, f1, f2", number=10000) 
print timeit.timeit("f1()", setup="from __main__ import f0, f1, f2", number=10000) 
print timeit.timeit("f2()", setup="from __main__ import f0, f1, f2", number=10000) 

產生輸出

0.13874912262 
0.103307008743 
0.10813999176 

我的zip函數可以更快完成嗎?

+2

'[子列表中項目的子項列表中的項目]'將使用任意長度的一級嵌套列表。 – thefourtheye 2015-01-04 14:07:14

+0

*「更好」*是什麼意思? – jonrsharpe 2015-01-04 14:08:43

+0

@jonrsharpe更快。名單很長,而且會發生很多。 – Joel 2015-01-04 14:10:07

回答

3

一點點時間建議名單理解是略高於itertools版本(短名單更快 - Hackaholic's answer提出相反是長期真名單):

>>> import timeit 
>>> timeit.timeit("[item for sublist in a for item in sublist]", 
        setup="import itertools; a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]") 
1.7200839519500732 
>>> timeit.timeit("list(itertools.chain.from_iterable(a))", 
        setup="import itertools; a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]") 
2.0097079277038574 

迭代方法的主要優勢是,如果你能避免構建整個列表,遍歷chain.from_iterable的輸出,而不是把它傳遞給list常量ructor。

如果你對數組做操作和性能是一個重要的考慮因素,可以考慮使用numpy,這雖然不是標準庫的一部分,是更快(一旦你的陣列):

>>> import numpy as np 
>>> a = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]) 
>>> a 
array([[ 1, 2], 
     [ 3, 4], 
     [ 5, 6], 
     [ 7, 8], 
     [ 9, 10]]) 
>>> a.ravel() 
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 
>>> timeit.timeit("a.ravel()", 
        setup="import numpy as np; a = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])") 
0.36390113830566406 
+0

我稍微修改了我的問題。所有的子列表都有長度2,我不關心列表的最終順序。與一些額外的東西拉鍊似乎幾乎綁定itertools。有沒有辦法再調整一下? – Joel 2015-01-05 01:40:13

+0

@Joel請提供一些背景*。如果不同的方法可以完全刪除它,那麼優化代碼的這一小部分沒有意義。同樣,如果避免構建整個列表,您可以從「itertools」中獲得最好的結果;你是否可以做到這一點取決於*你想要做什麼*而且,就目前而言,我們不知道這是什麼。 – jonrsharpe 2015-01-05 10:14:34

+0

我的問題是在我的問題中引用的編輯中的'f2'是否可以加速以擊敗'f1'。這是我的問題的本質。如果你必須有更多的上下文:我們有一張圖表中有成千上萬的邊緣需要隨機重新佈線。要做到這一點,請將列表弄平,將其混洗,並將相鄰的對連接在一起。然後我們再次收集數千條邊來重新佈線。然後再次。然後再次。 – Joel 2015-01-05 10:37:14

2
import itertools 
a = [[1,2], [3,4], [5,6], [7,8], [9,10]] 
list(itertools.chain.from_iterable(a)) 

輸出:

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

現在這裏比較時序:對小名單

>>> timeit.timeit("list(itertools.chain.from_iterable(a))",setup='import itertools;a = [[1,2], [3,4], [5,6], [7,8], [9,10]]') 
0.9853601455688477 
>>> timeit.timeit("[ y for x in a for y in x]",setup='a = [[1,2], [3,4], [5,6], [7,8], [9,10]]') 
0.9124641418457031 

的大名單:

這裏的結果爲什麼迭代器者優先:

>>> timeit.timeit("list(itertools.chain.from_iterable(a))",setup='import itertools;a = zip(range(100),range(100))',number=1000000) 
8.213459014892578 
>>> timeit.timeit("[ y for x in a for y in x]",setup='a=zip(range(100),range(100))',number=1000000) 
12.833590984344482 

從小名單,list comprehension是好的,但對於大的,你需要使用iterators

+8

你能否擴展一下如何改進列表理解版本? – jonrsharpe 2015-01-04 14:09:01