15

I want to initialize a multidimensional list. Basically, I want a 10x10 grid - a list of 10 lists each containing 10 items.

Each list value should be initialized to the integer 0.

The obvious way to do this in a one-liner: myList = [[0]*10]*10 won't work because it produces a list of 10 references to one list, so changing an item in any row changes it in all rows.

The documentation I've seen talks about using [:] to copy a list, but that still won't work when using the multiplier: myList = [0]*10; myList = myList[:]*10 has the same effect as myList = [[0]*10]*10.

Short of creating a loop of myList.append()s, is there a quick efficient way to initialize a list in this way?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
fdmillion
  • 4,823
  • 7
  • 45
  • 82
  • I think the `[:]` idea can work too, e.g. `[x[:] for x in [[0]*10]*10]`. – DSM Jul 14 '13 at 04:46
  • See [this question](https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly) to understand why `[[0]*10]*10` doesn't work as expected. – Aran-Fey May 29 '18 at 16:56

8 Answers8

27

You can do it quite efficiently with a list comprehension:

a = [[0] * number_cols for i in range(number_rows)]
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
cheeyos
  • 671
  • 4
  • 11
  • 2
    Nice, avoids the nested for loop that the obvious answer has, but only works if the value to which you want the array initialized is okay to be referenced multiple times, so not if you want the array populated with unique instances of a class. – Perkins Jul 14 '13 at 04:49
  • 1
    Note the data may now be accessed using array-like syntax: `a[col_num][row_num]` – ZX9 Sep 22 '16 at 19:39
  • I didn't make the change. Just edited now since this is the more natural way to represent matrices. – cheeyos Oct 18 '16 at 01:13
  • @Alex, you're right. The outer list is indexed first. – rkedge Nov 27 '19 at 19:26
13

This is a job for...the nested list comprehension!

[[0 for i in range(10)] for j in range(10)]
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
llb
  • 1,671
  • 10
  • 14
2

Just thought I'd add an answer because the question asked for the general n-dimensional case and I don't think that was answered yet. You can do this recursively for any number of dimensions with the following example:

n_dims = [3, 4, 5]

empty_list = 0
for n in n_dims:
    empty_list = [empty_list] * n

>>>empty_list
>>>[[[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]]]
jengel
  • 587
  • 4
  • 8
  • 3
    This has the same problem as described in the question - it creates many references to the same list. – ml-moron Mar 14 '16 at 22:36
2

An additional solution is to use NumPy library:

import numpy as np

zero_array = np.zeros((10, 10), dtype='int')

This can be easily converted to a regular python list with the .tolist() method if necessary.

Matt Eding
  • 917
  • 1
  • 8
  • 15
1

Here is a function which works for an arbitrary number of dimensions using recursive list comprehensions. It doesn't need any imports to work.

def init_list(dims, val):
    if len(dims) == 0:
        raise ValueError("Requires at least 1 dimension.")

    if len(dims) == 1:
        return [val for _ in range(dims[0])]

    return [init_list(dims[1:], val=val) for _ in range(dims[0])]

Example:

>>> init_list([3, 2, 1], val=0)
[[[0], [0]], [[0], [0]], [[0], [0]]]
user3448370
  • 11
  • 1
  • 1
0

You might actually need an array instead of some lists. Almost every time I see this "presized nested list" pattern, something is not quite right.

Ali Afshar
  • 40,967
  • 12
  • 95
  • 109
0

I found that to get what you mean you need to youse

import copy

def n_dim_list(dims, init_val):
    if not dims:
        return []
    lst = [init_val for i in range(dims[-1])]
    for d in dims[::-1][1::]:
        lst = [copy.deepcopy(lst) for i in range(d)]
return lst

Where dims is a list of length of the number of the dimentions you want and the content is the size of the requiered nd-list in every dimention. Not the most elegant but clear and does the job.

yoni
  • 69
  • 2
  • 6
-1

Yet another method, but using the OP's rejected method.

import numpy as np
myList = [[0]*10]*10
myList = np.array(myList)
l=myList.tolist()
myList=l

The output and testing below:

>>> l
[[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]]
>>> l[0][0]=100
>>> l
[[100, 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 output is unlike the expected clone of l[0].

Although this is not time efficient. It takes nearly 7 seconds for a 1000X1000 list, where as list comprehensions took only 0.0052158 seconds for the same.