views:

95

answers:

4

Hello, everyone!

I am trying to create a 2d matrix so that each cell contains a list of strings. Matrix dimensions are known before the creation and I need to have access to any element from the beginning (not populating a matrix dynamically). => I think some kind of preallocation of space is needed.

For example, I would like to have a 2X2 matrix:

[['A','B']          ['C'];
  ['d']       ['e','f','f']]

with support of traditional matrix access operations, like

(Matrix[2][2]).extend('d')

or

tmp = Matrix[2][2]
tmp.extend('d')
Matrix[2][2] = tmp

to manipulate with cells content.

How to accomplish it in python?

+2  A: 

Just as you wrote it:

>>> matrix = [["str1", "str2"], ["str3"], ["str4", "str5"]]
>>> matrix
[['str1', 'str2'], ['str3'], ['str4', 'str5']]
>>> matrix[0][1]
'str2'
>>> matrix[0][1] += "someText"
>>> matrix
[['str1', 'str2someText'], ['str3'], ['str4', 'str5']]
>>> matrix[0].extend(["str6"])
>>> matrix[0]
['str1', 'str2someText', 'str6']

Just think about 2D matrix as list of the lists.

Klark
A: 

You can either do it with the basic:

matrix = [
   [["s1","s2"], ["s3"]],
   [["s4"], ["s5"]]
]

or you can do it very genericially

from collections import defaultdict
m = defaultdict(lambda  : defaultdict(list))
m[0][0].append('s1')

In the defaultdict case you have a arbitrary matrix that you can use, any size and all the elements are arrays, to be manipulated accordingly.

koblas
Thanks for all of you!
Nik
m = defaultdict(lambda : defaultdict(list)) - is the best for my purposes!
Nik
A: 

One option is to write your own class, where you overload the [] operator. Take a look for that in here: http://www.penzilla.net/tutorials/python/classes/ . Acessing a 2d elment in 1d is y * rowSize + x. Extending the elements by writing an append function, which would use append rowSize times.

If you want to create a 2d matrix and you need to preallocate than, you could do the following:

x,y = 3,3
A = [ [None]*x for i in range(y) ]

You can replace None with the value you want. And you can use .extend to add additional values.

inf.ig.sh
A: 

First of all, what you describe is actually a 3 dimensional matrix since each 'cell' also has a dimension whose kth element of the jth column of the ith row could be accessed via matrix[i][j][k].

Regardless, if you'd like to preallocate a 2X2 matrix with every cell initialized to an empty list, this function will do it for you:

def alloc_matrix2d(W, H):
    """ Pre-allocate a 2D matrix of empty lists. """
    return [ [ [] for i in range(W) ] for j in range(H) ]

However you might think it's not working because I noticed that you said that you would like to have a 2X2 matrix like this:

[
    [
        ['A','B'], ['C']
    ],
    [
        ['d'], ['e','f','f']
    ]
]

and be able to use "traditional matrix access operations" to do this to it:

(Matrix[2][2]).extend('d')

Problem is that won't work even for the matrix shown and still wouldn't for one preallocated to 2X2 since both the row and column dimensions are out of range in either case. In Python all sequences are indexed from zero, so valid indices for a matrix with two rows of two elements each are [0][0], [0][1], [1][0], and [1][1] (ignoring possible negative indices which have a special meaning in Python). So using Matrix[2][2] is an attempt to access the third column of the third row of the matrix which don't exist and wouldn't even in a preallocated one with dimensions of 2X2.

Everything would be fine if you changed that statement to something like this using one of the valid pairs of index values (and with unnecessary parentheses removed):

Matrix[1][1].extend('d')

since it would not raise an IndexError and instead would result in the 2X2 matrix becoming:

[
    [
        ['A', 'B'], ['C']
    ],
    [
        ['d'], ['e', 'f', 'f', 'd']
    ]
]

Bonus Utility You didn't ask for one, but here's a handy function I wrote to help printing out arbitrarily sized 2D matrices of any type (represented as nested lists):

def repr_matrix2d(name, matrix):
    lines = ['{} = ['.format(name)]
    rows = []
    for row in range(len(matrix)):
        itemreprs = [repr(matrix[row][col]) for col in range(len(matrix[row]))]
        rows.append('\n    [\n        {}\n    ]'.format(', '.join(itemreprs)))
    lines.append('{}\n]'.format(','.join(rows)))

    return ''.join(lines)

Hope this helps.

martineau