Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python元组中高效的多个任意索引访问?_Python_Tuples_Slice - Fatal编程技术网

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

Python元组中高效的多个任意索引访问?,python,tuples,slice,Python,Tuples,Slice,我有一个很长的Python元组t。我想从t中尽可能高效地获取i1、i2、…、索引中的元素。最好的办法是什么 一种方法是: (1) result = [t[j] for j in (i1, i2, ..., iN)] 但这似乎会导致对元组进行N次单独的查找。有没有更快的办法?当Python执行如下操作时: (2) result = t[1:M:3] 我假设它不执行M/3单独的查找。(可能它使用位掩码并执行单拷贝操作?)有没有什么方法可以让我利用Python在(2)中所做的任何事情,

我有一个很长的Python元组
t
。我想从
t
中尽可能高效地获取
i1
i2
、…、
索引中的元素。最好的办法是什么

一种方法是:

(1)    result = [t[j] for j in (i1, i2, ..., iN)]
但这似乎会导致对元组进行N次单独的查找。有没有更快的办法?当Python执行如下操作时:

(2)    result = t[1:M:3]
我假设它不执行M/3单独的查找。(可能它使用位掩码并执行单拷贝操作?)有没有什么方法可以让我利用Python在(2)中所做的任何事情,使我的任意索引切片在单拷贝中发生


谢谢。

在列表理解中有一个隐式的
for
循环,我确信它以合理的效率迭代元组值。我认为你不可能为了提高效率而提高对列表的理解

如果您只需要这些值,您可能可以使用生成器表达式并避免构建列表,从而稍微节省时间或内存。

切片可能更有效,因为它有更多的约束:索引必须以固定数量的线性方式进行。列表理解可能是完全随机的,因此不可能进行优化


然而,对效率做出假设是危险的。尝试两种方法计时,看看是否有显著差异。

您列出的方法是从元组中获取元素的最佳方法。您通常不关心这些表达式中的性能-这是一个过早的优化,即使您这样做了,这些操作已经太慢了,即使进行了优化,也就是说,如果您优化访问,由于临时变量的引用计数等原因,循环本身仍然会很慢

如果您已经存在性能问题,或者这已经是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\u GET\u ITEM
来复制元素,但是请注意,使用C API并不是一件小事,可能会引入很多错误

3) 您可以将C数组与C API结合使用,例如使用
array.array的缓冲区接口将数据访问粘附到Python

4) 您可以将Cython与C数组和自定义Cython类型一起使用,以便从Python访问数据

5) 您可以同时使用Cython和
numpy

1)您确定需要加快操作速度吗

2) 另一个选项是
operator.itemgetter
:它返回由其索引选择的元组:

>>> t = tuple(string.ascii_uppercase)
>>> operator.itemgetter(13,19,4,21,1)(t)
('N', 'T', 'E', 'V', 'B')

操作符
模块是用C语言实现的,因此它的性能可能优于Python循环。

如果您要进行大量相同的查找,那么使用itemgetter可能是值得的

from operator import itemgetter
mygetter = itemgetter(i1, i2, ..., iN)
for tup in lots_of_tuples:
    result = mygetter(tup)
首先,创建itemgetter的开销是不值得的

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

显然,差异将取决于元组的长度、索引的数量等。

对内置序列类型的实例进行索引是最快的操作之一。在这些方法上进行切片比自己在循环中进行切片效率稍高的唯一原因是,它是用C编写的,而在Python中,循环以及(甚至隐式)调用方法的开销更大。另外,只有当
i1
iN
是相同数字的倍数加上某个常数时,才能应用于切片的技巧(如果有这样的技巧…你必须以任何方式复制每个项目)。你如何确定(i1…iN)?也许在效率(和简单性)方面会有所提高,但只有在更大范围内进行重写……这对我来说是一个有趣且令人惊讶的优化。您可以发布代码、性能测试和cProfile结果的链接供我们查看吗?谢谢您的提示和性能示例。我不知道itemgetter,它正好回答了我的问题。