Python 3.2 中的多维数组实现,以及与 C# 的相似之处






3.88/5 (7投票s)
一个具有负索引功能的的多维数组类。使用方式类似于 a[-2, -5, 3],适用于任何维度。
下载 multiray.py.zip (适用于 Python 3.x)[^]
下载 multiray.cs.zip (更新于 2011.08.05)[^]
引言
您可以轻松使用 Multiray
类来处理多维数组相关的问题。现在您可以下载 C# 版本
的 multiray,其结构与 Python 版本完全相同。
Using the Code
使用方法很简单- 使用预定义的维度初始化
Multiray
对象
Python
a = Multiray(2, 5, 20, 6);
C#
using multiray; MultiRay a = new MultiRay(2, 5, 20, 6);
- 将您的数据值分配给指定多索引的单元格
Python
#a[1, 4, 21, 1] will assert an overflow. a[1, 2, 18, 5] = "Any Object";
C#
//a[1, 4, 21, 1] will raise an exception. a[1, 2, 18, 5] = "Any Object";
- 循环方式类似于锯齿数组。使用
GetLength(d)
获取任何维度在索引 d 处的值。
Python
for i in range(a.GetLength(0)): for j in range(a.GetLength(1)): for k in range(a.GetLength(2)): for l in range(a.GetLength(3)): #do anything you want with #a[i, j, k, l]; print("a[{1:3}]={0}".format(a[i, j, k, l], a.Position));
C#
for (int i = 0; i < a.GetLength(0); i++) for (int j = 0; j < a.GetLength(1); j++) for (int k = 0; k < a.GetLength(2); k++) for (int l = 0; l < a.GetLength(3); l++) { a[i, j, k, l] = "Hello World"; Console.WriteLine("a[{0},{1},{2},{3}] = {4}" , i, j, k, l, a[i, j, k, l]); }
_EvaluateIndex
根据此原理计算给定索引元组的实际索引
- 如果 a 是一个 (I x J x K) 的三维数组;那么 a[i][j][k] 是数组 a 中的第 n 个元素。在
Multiray
实现中,n 的值由_EvaluateIndex
() 方法调用计算得出。 - 对于 D = 3,n 的计算方式如下
n = i*J*K + j*K + k;
n = i*J*K*T + j*K*T + k*K + t;
_EvaluateIndex
肯定会这样做Python
def _EvaluateIndex(self, keys, k): dLen = len(self.Dimensions); #attention! #check recursive deadline: if k == dLen: return keys[-1]; t = 1; #accumulator #multiply t with the given dimensions k to dLen for i in range(k, dLen): t *= self.Dimensions[i] t *= keys[k - 1]; return t + self._EvaluateIndex(keys, k=k+1);C#
private int _EvaluateIndex(int[] keyTuple, int k) { int dLen = this.Dimensions.Length; if (k == dLen) return keyTuple[keyTuple.Length - 1]; int t = 1; for (int i = k; i < dLen; i++) { t *= this.Dimensions[i]; } t *= keyTuple[k - 1]; return t + this._EvaluateIndex(keyTuple, k + 1); }
如何使用索引器使用 Multiray 对象?
- 解决方案是实现
__getitem__
和__setitem__
Python
def __getitem__(self, keyTuple): keys = self._CheckKeys(keyTuple); self.Position = self._EvaluateIndex(keys, k=1); return self._Arr2D[self.Position];
self._CheckKeys
进行检查和负索引的转换 (a[2,3,-2]);然后计算self.Position
,并将其作为索引传递给self._Arr2D
数组。
Python
def __setitem__(self, keyTuple, item): keys = self._CheckKeys(keyTuple); self.Position = self._EvaluateIndex(keys, k=1); self._Arr2D[self.Position] = item
C#
public object this[params int[] keyTuple] { get { int[] keys = this._CheckKeys(keyTuple); this.Position = this._EvaluateIndex(keys, 1); return this._Arr2D[this.Position]; } set { int[] keys = this._CheckKeys(keyTuple); this.Position = this._EvaluateIndex(keys, 1); this._Arr2D[this.Position] = value; } }
- 再次,
self._CheckKeys()
进行检查和操作
Python
def _CheckKeys(self, keyTuple): assert(len(keyTuple) == len(self.Dimensions)); keyList = list(keyTuple); limit = len(keyList); for i in range(limit): assert(keyList[i] < self.Dimensions[i] \ and keyList[i] >= -self.Dimensions[i]); #for minus indexes: #like a[1,-2] if keyList[i] < 0: keyList[i] += self.Dimensions[i]; return keyList;
C#
private int[] _CheckKeys(int[] keyTuple) { Debug.Assert(keyTuple.Length == this.Dimensions.Length); int limit = keyTuple.Length; int[] keyList = new int[limit]; for (int i = 0; i < limit; i++) { Debug.Assert(keyList[i] < this.Dimensions[i] && keyList[i] >= -this.Dimensions[i]); keyList[i] = keyTuple[i]; //for negative indexes //like a[1,-2] if (keyList[i] < 0) keyList[i] += this.Dimensions[i]; } return keyList; }
最后的话
- 我发现用逗号分隔的索引以元组的形式传递。因此,当我使用 a[1,2,3] 时,__getitem__ 接收 (1,2,3) 元组。
- 因此,目前不需要位置参数。
关注点
我遇到了无效的数学计算问题。在归纳法的帮助下,我最终实现了正确的功能。
历史
之前的版本缺少 C# 的实现。