2d array of lists in python

48,641

Solution 1

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. Other operations also work fine, for example,

>>> matrix[0].append('value')
>>> matrix[0]
[0, 0, 0, 0, 0, 'value']
>>> matrix[0].pop()
'value'
>>> 

Solution 2

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.

Solution 3

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.

Solution 4

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.

Share:
48,641
Nik
Author by

Nik

Updated on April 11, 2020

Comments

  • Nik
    Nik about 4 years

    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?

  • Nik
    Nik over 13 years
    m = defaultdict(lambda : defaultdict(list)) - is the best for my purposes!
  • martineau
    martineau over 13 years
    Just want to point out that this allocates a 3X3 2D matrix since x and y are each 3.
  • Metagrapher
    Metagrapher over 11 years
    if you need a 3D matrix, this will work for you: [[ [0]*x for i in range(y) ] for j in range(z)]
  • Bheid
    Bheid almost 6 years
    can you explain about m = defaultdict(lambda : defaultdict(list)) ?
  • koblas
    koblas almost 6 years
    defaultdict() takes a function for a parameter to create the element, using lambda:defaultdict(list) is creating a function taking no parameters returning a list. See docs.python.org/2/library/collections.html#defaultdict-objec‌​ts