Download multiray.py.zip for Python 3.x[^]
Download multiray.cs.zip (updated 05.08.2011)[^]
Introduction
You can easily make use of Multiray
class for issues regarding multidimensional arrays. Now you can download C# version
of multiray completely with the same structure as python version.
Using the Code
The usage is simple:
- Initialize
Multiray
object with predefined dimensions:
Python
a = Multiray(2, 5, 20, 6);
C#
using multiray;
MultiRay a = new MultiRay(2, 5, 20, 6);
- Assign your data values to multi-index specified cells:
Python
#a[1, 4, 21, 1] will assert an overflow.
a[1, 2, 18, 5] = "Any Object";
C#
a[1, 2, 18, 5] = "Any Object";
- Looping is somewhat like jagged arrays. Use
GetLength(d)
for any dimension with index 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
gets real index of given indexes-tuple with this principle:
- if a is a (I x J x K) three dimensional array; let a[i][j][k] nth item in a array. In
Multiray
implementation, n is evaluated by _EvaluateIndex
() method call. - for D = 3, n is thus:
n = i*J*K + j*K + k;
for D = 4(I x J x K x T :: i, j, k, t) n is thus:
n = i*J*K*T + j*K*T + k*K + t;
We multiply the first key with J, K and T; second key with K and T; third with T and fourth with 1So we need to multiply first index with keys[1]*keys[2]*keys[3] second key with keys[2]*keys[3] and so on..._EvaluateIndex
definitely do this:
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);
}
How is it possible using Multiray object with an indexer?
- Solution is implementing
__getitem__
and __setitem__
:
Python
def __getitem__(self, keyTuple):
keys = self._CheckKeys(keyTuple);
self.Position = self._EvaluateIndex(keys, k=1);
return self._Arr2D[self.Position];
self._CheckKeys
makes checks and conversion of minus indexes(a[2,3,-2]); then self.Position
is evaluated and is given as index to the self._Arr2D
array.
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;
}
}
- Again
self._CheckKeys()
makes checks and manipulations:
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];
if (keyList[i] < 0)
keyList[i] += this.Dimensions[i];
}
return keyList;
}
Last word
- I found out that "," delimeted indexes are passed in tuples. So when I use a[1,2,3] __getitem__ takes (1,2,3) tuple.
- So positional arguments not needed for now.
Points of Interest
I suffered from invalid mathematical evaluations. By the help of induction, I could eventually implement the right way of function.
History
The previous version lacked c sharp in advance.