如何在 Python 指针中有效地迭代数组?

Posted

技术标签:

【中文标题】如何在 Python 指针中有效地迭代数组?【英文标题】:How to iterate an array in Python pointer-likely and efficiently? 【发布时间】:2015-07-18 02:57:11 【问题描述】:

我是 Python 的新手,我想迭代一个数组以根据前面的元素计算下一个元素。我可以用 C++ 的方式来思考这个问题,但是如何在 Python 中使用 Numpy 或 Pandas 来实现这一点?我知道类似的方法是使用移位,但这种方法似乎效率不高。

以下是一个简单的斐波那契示例:

int arr[10];
arr[0] = 1;
arr[1] = 1;

int* pt = &arr[2];         <--get a iterator like a moving pointer
int count = 8;
while (count > 0)

    *pt = pt[-1] + pt[-2]; <--access previous k element based on current index
    count--;
    pt++;                  <--point to next element

for (int i = 0; i < 10; i++)
    cout << arr[i] << endl;

列表:

L = [1, 1]
while len(L) != 10:
    L.append(L[-1] + L[-2]) <--But I have to append element every time
print L

【问题讨论】:

你知道如何在 Python 中创建列表吗?您可以使用其append 方法附加到它,并将最后两个元素作为l[-1]l[-2] 您需要快速插入吗?也就是说,您是否特别需要链表结构?还是可以接受动态数组(连续内存)?如果你主要是迭代而不是插入(或者你所有的插入都在最后),那么 Python 的内置列表对象将是要走的路。 可以预分配底层数组:L = 10 * [0]; L[0] = L[1] = 1 如果列表原本是固定大小的怎么办? 这个 SO 中有很多 Python 选项,包括基于列表的选项。不过没有人使用指针:***.com/questions/494594/… 【参考方案1】:

直接numpy模仿你的C++是

arr=np.ones((10,))
for i in range(2,arr.shape[0]):
     arr[i]=arr[i-1]+arr[i-2]

制作:

array([  1.,   1.,   2.,   3.,   5.,   8.,  13.,  21.,  34.,  55.])

这在numpy 中可能不是最有效的方法,但这是讨论的开始。

大多数快速numpy 操作使用编译的c 代码,并且结果是缓冲的,因此执行快速顺序操作很棘手。最好考虑一下 numpy 操作同时在数组的所有项上并行执行(不考虑任何顺序)。例外是 ufunc cumsumcumprod - 累积进程,以及称为 at 的无缓冲 ufunc。我必须四处看看是否有办法使用这些工具之一来计算这个系列。

另一种选择是在 C 或 C++ 中实现计算并将其链接。 cython 是最方便的工具。


http://wiki.scipy.org/Cookbook/Ctypes#head-6a582bd7b101bca0df6e5631a06e2d1d76e35a95 是使用ctypesc 代码与numpy 计算斐波那契的示例。

http://numpy-discussion.10968.n7.nabble.com/vectorizing-recursive-sequences-td35532.html 描述了一种计算这个系列的更巧妙的方法。这取决于 ufunc 采用 out 数组。作者承认这也取决于实现细节,尤其是计算没有缓冲。

arr=np.ones((10,))
np.add(arr[:-2], arr[1:-1], out=arr[2:])

第一个 2 个参数的元素逐个元素添加,并存储在 out 数组中。

arr[2:] = arr[:-2]+arr[1:-1]

由于缓冲而无法工作


http://docs.cython.org/src/tutorial/cython_tutorial.html#fibonacci-fun

是斐波那契的 Cython 示例。它应该很快,但它只是打印结果,而不是将它们累积在一个数组中。不过,将结果存储在 cython 数组或 memoryview 中的 Cython/c 版本应该不难。

这是一个cython 脚本,可以保存为pyx,编译和导入。它可以改进为有用性和速度,但足以测试这个概念:

import numpy as np
narr = np.ones((10,), dtype=np.dtype("i"))
cdef int [:] narr_view = narr

cpdef void fib(int[:] arr):
    I = arr.shape[0]
    for i in range(2,I):
        arr[i] = arr[i-2]+arr[i-1]
fib(narr_view)
print 'fib arr:', narr

【讨论】:

非常感谢!这正是我想知道的。 我发现了一些其他的想法。

以上是关于如何在 Python 指针中有效地迭代数组?的主要内容,如果未能解决你的问题,请参考以下文章

如何在python 3中有效地将原始字节写入numpy数组数据

如何有效地对抽象列表进行嵌套迭代?

从 numpy 数组中删除 None 的有效方法

如何有效地迭代 Java Map 中的每个条目?

如何有效地乘以重复行的火炬张量而不将所有行存储在内存中或迭代?

在比较列表中的元素时,如何有效地迭代并提高 O(n^2) 的时间复杂度?