2015-01-04 44 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