views:

762

answers:

4

Hi,

I am writing some small games in Python with Pygame & Pyglet as hobby projects.

A class for 2D array would be very handy. I use py2exe to send the games to relatives/friends and numpy is just too big and most of it's features are unnecessary for my requirements.

Could you suggest a Python module/recipe I could use for this.

-- Chirag

[Edit]: List of lists would be usable as mentioned below by MatrixFrog and zvoase. But it is pretty primitive. A class with methods to insert/delete rows and columns as well as to rotate/flip the array would make it very easy and reusable too. dicts are good for sparse arrays only.

Thank you for your ideas.

+3  A: 

The simplest approach would just be to use nested lists:

>>> matrix = [[0] * num_cols] * num_rows
>>> matrix[i][j] = 'value' # row i, column j, value 'value'
>>> print repr(matrix[i][j])
'value'

Alternatively, if you’re going to be dealing with sparse matrices (i.e. matrices with a lot of empty or zero values), it might be more efficient to use nested dictionaries. In this case, you could implement setter and getter functions which will operate on a matrix, like so:

def get_element(mat, i, j, default=None):
    # This will also set the accessed row to a dictionary.
    row = mat.setdefault(i, {})
    return row.setdefault(j, default)

def set_element(mat, i, j, value):
    row = mat.setdefault(i, {})
    row[j] = value

And then you would use them like this:

>>> matrix = {}
>>> set_element(matrix, 2, 3, 'value') # row 2, column 3, value 'value'
>>> print matrix
{2: {3: 'value'}}
>>> print repr(get_element(matrix, 2, 3))
'value'

If you wanted, you could implement a Matrix class which implemented these methods, but that might be overkill:

class Matrix(object):
    def __init__(self, initmat=None, default=0):
        if initmat is None: initmat = {}
        self._mat = initmat
        self._default = default
    def __getitem__(self, pos):
        i, j = pos
        return self._mat.setdefault(i, {}).setdefault(j, self._default)  
    def __setitem__(self, pos, value):
        i, j = pos
        self._mat.setdefault(i, {})[j] = value
    def __repr__(self):
        return 'Matrix(%r, %r)' % (self._mat, self._default)

>>> m = Matrix()
>>> m[2,3] = 'value'
>>> print m[2,3]
'value'
>>> m
Matrix({2: {3: 'value'}}, 0)
zvoase
Excellent answer.
Adam Bernier
Added the "Matrix" class example just for the kicks. :)
nosklo
+5  A: 

How about using a defaultdict?

>>> import collections
>>> Matrix = lambda: collections.defaultdict(int)
>>> m = Matrix()
>>> m[3,2] = 6
>>> print m[3,4]   # deliberate typo :-)
0
>>> m[3,2] += 4
>>> print m[3,2]
10
>>> print m
defaultdict(<type 'int'>, {(3, 2): 10, (3, 4): 0})

As the underlying dict uses tuples as keys, this supports 1D, 2D, 3D, ... matrices.

+1 that would be faster than using nested dicts. flat is better than nested
nosklo
+2  A: 

Maybe pyeuclid matches your needs -- (dated but usable) formatted docs are here, up-to-date docs in ReST format are in this text file in the pyeuclid sources (to do your own formatting of ReST text, use the docutils).

Alex Martelli
It sounds like the OP wants general 2D arrays, not just the 3x3 and 4x4 provided by pyeuclid. However, I'm upvoting this anyway because (1) it seems like this module was created specifically for Pygame and (2) it was created by the guy who would later go on to create pyglet! Oh, and (3) maybe those small matrices are what OP wants after all.
John Y
A: 

I wrote the class. Don't know if it is a good or redundant but... Posted it here http://bitbucket.org/pieceofpeace/container2d/

chirag