I have a little Java problem I want to translate to Python. Therefor I need a multidimensional array. In Java it looks like:
double dArray[][][] = new double[x.l
Multidimensional arrays are a little murky. There are few reasons for using them and many reasons for thinking twice and using something else that more properly reflects what you're doing. [Hint. your question was thin on context ;-) ]
If you're doing matrix math, then use numpy
.
However, some folks have worked with languages that force them to use multi-dimensional arrays because it's all they've got. If your as old as I am (I started programming in the 70's) then you may remember the days when multidimensional arrays were the only data structure you had. Or, your experience may have limited you to languages where you had to morph your problem into multi-dimensional arrays.
Say you have a collection n 3D points. Each point has an x, y, z, and time value. Is this an n x 4 array? Or a 4 * n array? Not really.
Since each point has 4 fixed values, this is more properly a list of tuples.
a = [ ( x, y, z, t ), ( x, y, z, t ), ... ]
Better still, we could represent this as a list of objects.
class Point( object ):
def __init__( self, x, y, z, t ):
self.x, self.y, self.z, self.t = x, y, z, t
a = [ Point(x,y,x,t), Point(x,y,z,t), ... ]
If you are OK using sparse arrays, you could use a dict to store your values. Python's dicts allow you to use tuples as keys, as such, you could assign to and access elements of the "sparse array" (which is really a dict here) like this:
d = {}
d[0,2,7] = 123 # assign 123 to x=0, y=2, z=7
v = d[0,2,7]
You can create it using nested lists:
matrix = [[a,b],[c,d],[e,f]]
If it has to be dynamic it's more complicated, why not write a small class yourself?
class Matrix(object):
def __init__(self, rows, columns, default=0):
self.m = []
for i in range(rows):
self.m.append([default for j in range(columns)])
def __getitem__(self, index):
return self.m[index]
This can be used like this:
m = Matrix(10,5)
m[3][6] = 7
print m[3][6] // -> 7
I'm sure one could implement it much more efficient. :)
If you need multidimensional arrays you can either create an array and calculate the offset or you'd use arrays in arrays in arrays, which can be pretty bad for memory. (Could be faster though…) I've implemented the first idea like this:
class Matrix(object):
def __init__(self, *dims):
self._shortcuts = [i for i in self._create_shortcuts(dims)]
self._li = [None] * (self._shortcuts.pop())
self._shortcuts.reverse()
def _create_shortcuts(self, dims):
dimList = list(dims)
dimList.reverse()
number = 1
yield 1
for i in dimList:
number *= i
yield number
def _flat_index(self, index):
if len(index) != len(self._shortcuts):
raise TypeError()
flatIndex = 0
for i, num in enumerate(index):
flatIndex += num * self._shortcuts[i]
return flatIndex
def __getitem__(self, index):
return self._li[self._flat_index(index)]
def __setitem__(self, index, value):
self._li[self._flat_index(index)] = value
Can be used like this:
m = Matrix(4,5,2,6)
m[2,3,1,3] = 'x'
m[2,3,1,3] // -> 'x'
Here's a quick way to create a nested 3-dimensional list initialized with zeros:
# dim1, dim2, dim3 are the dimensions of the array
a =[[[0 for _ in range(dim1)] for _ in range(dim2)] for _ in range(dim1) ]
a[0][0][0] = 1
this is a list of lists of lists, a bit more flexible than an array, you can do:
a[0][0] = [1,2,3,4]
to replace a whole row in the array, or even abuse it like that:
a[0] = "Ouch"
print a[0][0] #will print "O", since strings are indexable the same way as lists
print a[0][0][0] #will raise an error, since "O" isn't indexable
but if you need performance, then I agree that numpy is the way to go.
Also, beware of:
a = [[[0] * 5]*5]*5]
If you try a[0][0][0]=7
on the object above, you will see what's wrong with that.
Easy, when using numpy:
b = ones((2,3,4)) # creates a 2x3x4 array containing all ones.
'ones' can be replaced with 'zeros'
To create a standard python array of arrays of arbitrary size:
a = [[0]*cols for _ in [0]*rows]
It is accessed like this:
a[0][1] = 5 # set cell at row 0, col 1 to 5
A small python gotcha that's worth mentioning: It is tempting to just type
a = [[0]*cols]*rows
but that'll copy the same column array to each row, resulting in unwanted behaviour. Namely:
>>> a[0][0] = 5
>>> print a[1][0]
5