我有一个很长的Python元组t
。我想尽可能高效地从i1
抓取i2
,iN
,...,t
的索引元素。什么是最好的方式?
一种方法是:
(1) result = [t[j] for j in (i1, i2, ..., iN)]
但这似乎会导致N个单独的查找到元组。有更快的方法吗?当Python做这样的切片时:
(2) result = t[1:M:3]
我假设它不执行M / 3单独查找。 (也许它使用位掩码并执行单个复制操作?)是否有一些方法可以利用Python中的任何内容(2)使我的任意索引切片在一个副本中发生?
感谢。
答案 0 :(得分:7)
如果您正在进行大量相同的查找,则可能需要使用itemgetter
from operator import itemgetter
mygetter = itemgetter(i1, i2, ..., iN)
for tup in lots_of_tuples:
result = mygetter(tup)
对于一次性,创建项目集的开销是不值得的
iPython中的快速测试显示:
In [1]: import random
In [2]: from operator import itemgetter
In [3]: t=tuple(range(1000))
In [4]: idxs = tuple(random.randrange(1000) for i in range(20))
In [5]: timeit [t[i] for i in idxs]
100000 loops, best of 3: 2.09 us per loop
In [6]: mygetter = itemgetter(*idxs)
In [7]: timeit mygetter(t)
1000000 loops, best of 3: 596 ns per loop
显然,差异将取决于元组的长度,索引的数量等。
答案 1 :(得分:2)
您列出的那个是从元组中获取元素的最佳方式。你通常不关心这些表达式的性能 - 这是一个过早的优化,即使你这样做,即使你进行了优化,这样的操作也已经太慢了,即如果你优化访问,循环本身仍然会因为引用计数临时变量等。
如果您已经遇到性能问题,或者这已经是CPU密码的一部分,您可以尝试以下几种方法:
1)numpy
数组:
>>> arr = np.array(xrange(2000))
>>> mask = np.array([True]*2000)
>>> mask = np.array([False]*2000)
>>> mask[3] = True
>>> mask[300] = True
>>> arr[mask]
array([ 3, 300])
2)您可以使用C API来复制使用PyTuple_GET_ITEM
直接访问内部数组的元素,但要注意使用C API并不是一件容易的事,并且会引入很多错误。
3)您可以将C数组与C API一起使用,例如, array.array
的缓冲区接口,用于粘合对Python的数据访问。
4)您可以将Cython与C数组和自定义Cython类型一起用于Python的数据访问。
5)您可以一起使用Cython和numpy
。
答案 2 :(得分:0)
在列表推导中有一个隐式for
循环,我很确定它是以合理的效率迭代元组值。我不认为你可以提高列表理解效率。
如果您只需要这些值,您可以使用生成器表达式并避免构建列表,以节省时间或内存。
答案 3 :(得分:0)
切片可以更有效,因为它有更多的约束:索引必须以线性方式进行固定量。列表理解可以是完全随机的,因此无法进行优化。
对效率做出假设仍然是危险的。尝试两种方式,看看是否存在显着差异。
答案 4 :(得分:0)
1)您确定需要更快的操作吗?
2)另一个选项是operator.itemgetter
:它返回由其索引选择的元组:
>>> t = tuple(string.ascii_uppercase)
>>> operator.itemgetter(13,19,4,21,1)(t)
('N', 'T', 'E', 'V', 'B')
operator
模块在C中实现,因此可能胜过Python循环。