Python元组中的高效多任意索引访问?

时间:2011-08-30 19:31:34

标签: python tuples slice

我有一个很长的Python元组t。我想尽可能高效地从i1抓取i2iN,...,t的索引元素。什么是最好的方式?

一种方法是:

(1)    result = [t[j] for j in (i1, i2, ..., iN)]

但这似乎会导致N个单独的查找到元组。有更快的方法吗?当Python做这样的切片时:

(2)    result = t[1:M:3]

我假设它不执行M / 3单独查找。 (也许它使用位掩码并执行单个复制操作?)是否有一些方法可以利用Python中的任何内容(2)使我的任意索引切片在一个副本中发生?

感谢。

5 个答案:

答案 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循环。