简体   繁体   中英

Initializing an n-dimensional matrix elegantly in Python

There have been a couple questions on SO about how to initialize a 2-dimensional matrix, with the answer being something like this:

matrix = [[0 for x in range(10)] for x in range(10)]

Is there any way to generalize this to n dimensions without using for blocks or writing out a really long nested list comprehension?

As integers are immutable you can reduce your code to:

matrix = [[0] * 10 for x in range(10)]

As @iCodez mentioned in comments if NumPy is an option you can simply do:

import numpy as np                                              
matrix = np.zeros((10, 10)) 

If you really want a matrix, np.zeros and np.ones can quickly create such a 2 dimensional array for instantiating a matrix:

import numpy as np
my_matrix = np.matrix(np.zeros((10,10)))

To generalize to n dimensions, you can't use a matrix, which by definition is 2 dimensional:

n_dimensions = 3
width = 10

n_dimensional_array = np.ones((width,) * n_dimensions)

I agree that if numpy is an option, it's a much easier way to work with matrices. I highly recommend it.

That being said, this recursive function is a reasonable way to generalize your code to n dimensions. The first parameter is a list or tuple specifying how large each dimension should be (and, indirectly, how many dimensions). The second parameter is the constant value to fill the matrix with (in your example, 0 ):

def init(sizes, value=0):
    if (len(sizes) == 1):
        return [value] * sizes[0]
    else:

        # old code - fixed per comment. This method does not create
        # sizes[0] *new* lists, it just repeats the same list
        # sizes[0] times. This causes unexpected behavior when you
        # try to set an item in a list and all of its siblings get
        # the same change
        # return [init(sizes[1:], value)] * sizes[0]

        # this method works better; it creates a new list each time through
        return [init(sizes[1:], value) for i in xrange(sizes[0])]

matrix = init((2,3,4), 5)
matrix[0][0][0] = 100 # setting value per request in comment
print matrix
>>> [[[100, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]], [[5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]]]

N-dimensional arrays are a little hard to print on a 2D screen, but you can see the structure of matrix a little more easily in the snippet below which I manually indented. It's an array of length 2, containing arrays of length 3, containing arrays of length 4, where every value is set to 5:

[
    [
        [100, 5, 5, 5],
        [5, 5, 5, 5],
        [5, 5, 5, 5]
    ],
    [
        [5, 5, 5, 5],
        [5, 5, 5, 5],
        [5, 5, 5, 5]
    ]
]

@brian-putman was faster and better... anyway, this is my solution:

init = lambda x, y: [init(x, y-1) if y>1 else 0 for _ in xrange(x)]

that generates only square matrices of size x filled with zeroes in y dimensions. called like this

init(5, 3)

[[[0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0]],
 [[0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0]],
 [[0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0]],
 [[0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0]],
 [[0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0]]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM