1

I would like to create a python multi-dimensional empty list without very long codes. So I tried this:

a = [[[]] * 2] * 2  

It turns out that when I print(a), I got the multi-dimensional empty list:

[[[], []], [[], []]]

But when I append something into one of the empty list:

a[0][0].append(np.array((1.5,2.5)))  

All the empty lists got this np.array:

[[[array([1.5, 2.5])], [array([1.5, 2.5])]], [[array([1.5, 2.5])], [array([1.5, 2.5])]]]  

But if I create the multi-dimensional empty list like below:

b = []  
for i in range(2):   
    c = []  
    for j in range(2):  
        c.append(([]))  
    b.append(c)  

It works. When I print(b), I still got:

[[[], []], [[], []]]  

But when I do

b[0][0].append(np.array((1.6,2.6))) 

then print(b), I got:

[[[array([1.6, 2.6])], []], [[], []]]  

which is what I want.

Why is does happen?

I am using Python 3.6.8

This is my codes:

This is wrong:

a = [[[]] * 2] * 2  
print(a)  
a[0][0].append(np.array((1.5,2.5)))  
print(a)  

This is what I want:

b = []  
for i in range(2):  
    c = []  
    for j in range(2):  
        c.append(([]))  
    b.append(c)  
print(b)  
b[0][0].append(np.array((1.6,2.6)))  
print(b)  

Why a = [[[]] * 2] * 2 cannot work, and how can I create this shortly? Thanks!

Paritosh Singh
  • 6,034
  • 2
  • 14
  • 33
jizhekf
  • 21
  • 2

2 Answers2

1

Well, you did:

[[]]

This creates one element list containing list. But when you do:

[[]] * 4

this creates 4 element list, each containing the same element []. Do something like this:

for v in [[]] * 4:
    print(id(v))

and it prints:

46970800
46970800
46970800
46970800

If you want new list object every time you need something like this:

[ [] for _ in range(4) ]

instead of

[[]] * 4

First will create list of 4 lists, each unique. Second will create list of 4 lists, each the same.

Radosław Cybulski
  • 2,952
  • 10
  • 21
  • Yeah, it's very helpful to print the id(...) of each element. Then I tried the addition of lists and found that a = [[]] + [[]], then got a is [[], []] and each [] in this a has a different memory location! But list multiplication surely replicates the same memory location. It's not the same rule for + and *. Your explanation is very helpful, thank you very much! – jizhekf Jul 21 '19 at 09:30
0

It's not that one thing works and another doesn't, it's that you expect a different result. Each [] creates a list, but that list is mutable; list multiplication doesn't create new elements but new references to them, so [[]]*2 has contains two references to the same inner list. There isn't a concept of multi-dimensional list, it's just a list holding other lists. In the for loop you ran [] multiple times, creating distinct lists.

Basically, even though [[]]*2 looks like [[], []], it's actually like b after a = []; b = [a, a], while [[], []] is like a1 = []; a2 = []; b = [a1, a2].

One way to write the list creation structure more compactly is using a list comprehension:

listoflists = [[[] for i in range(2)] for j in range(2)]

Another option is to use a structure that does support multiple dimensions, such as NumPy's ndarray:

>>> import numpy
>>> a = numpy.ndarray((2,2), numpy.object)
>>> a
array([[None, None],
       [None, None]], dtype=object)

But this is built for matrices, so you don't have the independent lengths of lists.

Some parts of the standard library support using factory functions instead of prototype objects for this reason, such as collections.defaultdict(list).

Yann Vernier
  • 15,414
  • 2
  • 28
  • 26