将numpy数组转换为元组

166

注意: 这里要求与通常的元组转数组相反。

我需要将一个参数作为嵌套元组传递给一个(被封装的C++)函数。例如,以下代码有效。

X = MyFunction( ((2,2),(2,-2)) )

以下内容满足要求

X = MyFunction( numpy.array(((2,2),(2,-2))) )
X = MyFunction( [[2,2],[2,-2]] )

不幸的是,我想使用的参数以numpy数组的形式提供给我。该数组始终具有2xN的尺寸,其中N可能非常大。

有没有一种简单的方法将其转换为元组?我知道可以通过循环创建一个新元组,但希望有一些numpy数组提供的好用的方式。

如果不能如我所希望的那样轻松地完成此操作,那么通过循环或其他方式完成这个过程的最佳方法是什么?

6个回答

234
>>> arr = numpy.array(((2,2),(2,-2)))
>>> tuple(map(tuple, arr))
((2, 2), (2, -2))

85
对于一个简单的一维数组 tuple(arr) - FindOutIslamNow

38

下面是一个能完成此操作的函数:

def totuple(a):
    try:
        return tuple(totuple(i) for i in a)
    except TypeError:
        return a

还有一个例子:

>>> array = numpy.array(((2,2),(2,-2)))
>>> totuple(array)
((2, 2), (2, -2))

3
好的概括。作为一个 Python 新手,我不确定在一个几乎和非异常状态一样常见的条件下使用异常是否被认为是良好的编码风格。至少在 C++ 中,通过异常来控制流程通常是被反对的。如果测试 type(a)==numpy.ndarray 是否更好呢?请注意,这不会改变原始意义。 - Mike
12
因为Python中的“鸭子类型”和EAFT概念,这是相当普遍的。这个链接可以了解更多:http://docs.python.org/glossary.html#term-duck-typing。这种方法的优点是它将把任何嵌套序列转换为嵌套元组,而不仅仅是数组。我应该做的一件事是指定except块要处理哪些错误,现在我已经改正了。 - Bi Rico
4
在C++中,异常处理相对于条件语句来说速度较慢,这有多种原因。在Python中,它们在性能方面大致相同 - 这是我们需要摒弃C++直觉的地方之一。 - dbn
1
这个解决方案完全符合我的需求。谢谢! - Antoine Neidecker

18

我不满意,最终使用了这个:

>>> a=numpy.array([[1,2,3],[4,5,6]])
>>> a
array([[1, 2, 3],
       [4, 5, 6]])

>>> tuple(a.reshape(1, -1)[0])
(1, 2, 3, 4, 5, 6)

我不知道它是否更快,但它看起来更有效 ;)


8
那个元组的形状不是我想要的。 - Mike
这看起来像是一种不错的零拷贝方式来哈希数组。 - Ludecan
不,它需要相同的时间(请原谅丑陋的格式):

%%

import numpy as np n = 10000 a = np.array([list(range(n)) for i in range(n)])

%%

%timeit hash(tuple(map(tuple, a)))
3.59 s ± 70.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%

%timeit hash(tuple(map(tuple, a)))
3.53 s ± 47.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
- Ludecan

9
另一个选项。
tuple([tuple(row) for row in myarray])

如果您要将NumPy数组传递给C++函数,您可能还希望考虑使用Cython或SWIG。


那不能转换为元组。要转换成列表吗? - Peter
你试过了吗?当我运行它时,它会生成一个元组。请注意,最后调用的函数是tuple,它返回一个元组。如果你只有 [...] 部分而没有外部的元组,你将得到一个元组列表。 - Greg von Winckel
有更快的方法吗? - Vicrobot
6
可以省略中括号,即使用 tuple(tuple(row) for row in myarray),避免创建中间的列表。 - norok2

5

如果你喜欢冗长的代码,这里有另外一种方式

tuple(tuple(a_m.tolist()) for a_m in a )

from numpy import array
a = array([[1, 2],
           [3, 4]])
tuple(tuple(a_m.tolist()) for a_m in a )

输出为 ((1, 2), (3, 4))
注意仅使用 (tuple(a_m.tolist()) for a_m in a ) 将会给出一个生成器表达式。 这种方法受到了 @norok2 对 Greg von Winckel's answer 的评论的启发。

0
这是一个递归解决方案,可以将任意嵌套的可迭代序列转换为元组。
from collections.abc import Iterable
import numpy as np

npArr = np.array(((2,2),(2,-2)))

def func(val):
    if not isinstance(val, Iterable):
        return val
    return tuple(func(elem) for elem in val)

# # One-liner
# func = lambda val: tuple(func(elem) for elem in val) if isinstance(val, Iterable) else val

res = func(npArr)
print(f"{res = }")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接