# Multidimensional collections

By Martin McBride, 2020-02-27
Tags: len 2d list
Categories: magic methods In the article on magic methods for collections we saw how to implement collection behaviours for our example matrix class. We implemented support of built-in function len, support for for loops and the in operator. We also saw how to might implement del, although our 2 by 2 matrix doesn't allow it.

For getting and setting elements, we implemented __getitem__ and __setitem__ as if the matrix was a list of 4 elements. In thi sarticle we will see how to improve that.

## Supporting two dimensional selection

Our Matrix is a 2D array, so wouldn't it be nice to support (row, column) style selection? It would be nice if we could use a syntax like:

a[0, 1]     #row 0, columns 1


Well we can! The numpy library does exactly this, and we can easily support this with our Matrix class.

If you are familiar with dictionaries, you will know that a dictionary is indexed by keys rather than integers. A key can be an integer, or a string, but it can also be a tuple:

d = dict()
d = 0
d['two'] = 2
d[(0, 1)] = 3
print(d)


This gives the result:

{0: 0, 'two': 2, (0, 1): 3}


Thanks to the magic of tuple packing we can write d[(0, 1)] as d[0, 1]. So we can do this:

d[0, 1] = 10
print(d)


which gives:

{0: 0, 'two': 2, (0, 1): 10}


We need to do a similar thing with our matrix class.

## Two dimensional getters and setters

Previously our getter and setter accepted and index of the item in list of length 4:

def __getitem__(self, i):
return self.data[i]


But now instead we want to pass in a tuple (row, col). So we need to modify our code like this:

def __getitem__(self, t):
row, col = t
return self.data[row*2 + col]


We can now do this:

m = Matrix(1, 2, 3, 4)
print(m[1, 0])


This prints matrix row 1, column 0, which is the value 3.

We can do a similar thing with the setter:

def __setitem__(self, t, value):
row, col = t
self.data[row*2 + col] = value


which allows us to do this:

m[0, 1] = 5
print(m)


The matrix has now been updated, with row 0 column 1 set to 5:

[1, 5][3, 4]