一般问题:假设您必须在循环中执行此操作,那么在效率方面是否存在构建列表的优选样式?例如,这些选项之一是建立整数列表的最佳选择:
mylist = []
for x, y in mystuff:
# x, y are strings that need to be
# added sequentially to list
mylist.extend([int(x), int(y)])
与
for x, y in mystuff:
mylist.append(int(x))
mylist.append(int(y))
还是其他人?如果相关,可以使用scipy / numpy。感谢。
答案 0 :(得分:11)
如果你需要像这样进行微观优化,那么了解最快速度的唯一方法就是测试。
简短版本是:append
比extend
快,而Joran Beasley的建议itertools.chain.from_iterable
略快于其中任何一项,但只有当您用map
取代import itertools
import timeit
def makestuff(count):
for i in range(count):
yield (i, i)
def f_extend(mystuff):
mylist = []
for x, y in mystuff:
mylist.extend([int(x), int(y)])
return mylist
def f_append(mystuff):
mylist = []
for x, y in mystuff:
mylist.append(int(x))
mylist.append(int(y))
return mylist
def f_chainmap(mystuff):
return list(map(int, itertools.chain(*mystuff)))
def f_chaincomp(mystuff):
return [int(x) for x in itertools.chain(*mystuff)]
def f_chainfrommap(mystuff):
return list(map(int, itertools.chain.from_iterable(mystuff)))
def f_chainfromcomp(mystuff):
return [int(x) for x in itertools.chain.from_iterable(mystuff)]
def f_reducecompcomp(mystuff):
return [int(x) for x in reduce(operator.iadd, (list(y) for y in mystuff), [])]
def f_reducecompmap(mystuff):
return [int(x) for x in reduce(operator.iadd, map(list, mystuff), [])]
try:
import numpy
def f_numpy(mystuff):
return numpy.array(mystuff).flatten().tolist()
def f_numpy2(mystuff):
return numpy.array(list(mystuff)).flatten().tolist()
except:
pass
if __name__ == '__main__':
import sys
main = sys.modules['__main__']
count = int(sys.argv[1]) if len(sys.argv) > 1 else 10000
for f in dir(main):
if f.startswith('f_'):
func = getattr(main, f)
mystuff = makestuff(count)
testfunc = lambda: func(mystuff)
print('{}: {}'.format(f, timeit.timeit(testfunc, number=count)))
时列表理解。
所以:
map
对于Python 2,我尝试了list
版本而没有额外的list
,而且速度略快,但仍然没有竞争力。当然,对于Python 3,$ python testlister.py 1000000
f_append: 1.34638285637
f_chaincomp: 2.12710499763
f_chainfromcomp: 1.20806899071
f_chainfrommap: 2.77231812477
f_chainmap: 3.67478609085
f_extend: 1.38338398933
f_numpy: 5.52979397774
f_numpy2: 7.5826470852
f_reducecompcomp: 2.17834687233
f_reducecompmap: 3.16517782211
$ python3 ./testlister.py 1000000
f_append: 0.9949617639649659
f_chaincomp: 2.0521950440015644
f_chainfromcomp: 0.9724521590862423
f_chainfrommap: 2.5558998831082135
f_chainmap: 3.5766013460233808
f_extend: 1.149905970087275
f_reducecompcomp: 2.2112889911513776
f_reducecompmap: 1.9317334480583668
是必需的。
以下是我的时间:
python
我的python3
是Apple的股票Python 2.7.2,而itertools
是python.org 3.3.0,都是64位,都是OS X 10.8.2,2012年中期MacBook Pro配备2.2GHz i7和4GB。
如果你在POSIX平台上使用32位Python,我过去已经注意到在不太遥远的过去的某个地方,迭代器得到了一个优化,似乎加快了{{{ 1位在64位版本中,但在32位中减慢速度。因此,在这种情况下,您可能会发现append
获胜。 (一如既往,在您真正关心优化的平台上进行测试。)
Ashwini Chaudhary与Flattening a shallow list in Python相关联,后者与finding elements in python association lists efficiently有关。我怀疑我的结果和他们的结果之间的区别是2.6.0和2.7.2 / 3.3.0之间的迭代器的改进,但我们明确使用2元素元素而不是更大元素的事实可能更重要
此外,至少有一个答案声称reduce
是最快的。原帖中的reduce
实现都非常慢,但我能够提出更快的版本。他们仍然没有与append
或chain.from_iterable
竞争,但他们是在正确的球场。
f_numpy
函数是heltonbiker的实现。由于mystuff
是一个2D迭代器,这实际上只是生成一个包装迭代器的0D数组,因此所有numpy
都可以增加开销。我能够提出一个生成一维迭代器数组的实现,但这甚至更慢,因为现在所有numpy
都可以做到经常增加N次开销。我可以获得2D整数数组的唯一方法是首先调用list
,就像f_numpy2
一样,这使得事情变得更慢。 (公平地说,在其他函数中添加额外的list
也会减慢它们的速度,但不会像numpy
那样差。)
然而,我很有可能在这里消隐,并且有一种合理的方法可以在这里使用numpy
。当然,如果您确定mystuff
中的顶级mystuff
或每个元素都是list
或tuple
,那么您可以写出更好的内容 - 如果可以的话重新设计你的应用程序,这样你首先得到一个2D numpy.array
,而不是一般的序列序列,这将是一个完全不同的故事。但是如果你只是对序列进行一般的2D迭代,那么对于这个用例似乎并不是很好。
答案 1 :(得分:2)
>>> my_list = [[1,2],[3,4]]
>>> flat_list_generator = itertools.chain.from_iterable(my_list) #flatten (note : its a generator!)
>>> map(int,flat_list_generator ) #map to int type (since OP made them ints explicitly)
[1, 2, 3, 4]
我认为是你想要的
答案 2 :(得分:2)
如果mystuff
是一对配对列表,那么您可以使用Numpy执行以下操作:
result = numpy.array(mystuff, dtype=float).flatten()
或者可选择将其列为一个列表:
result = numpy.array(mystuff, dtype=float).flatten().tolist()
从我的定性经验来看,这些数组创建程序非常快。