14

I simply want to create an empty 10*3*2 array with Python.

I first thought of these one, but this is not working:

parameters = [ [ [] * 2 ]*3 ] * 10

this gives me a vector of ten vectors, with three [] elements in it:

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

that is , if I want to access parameters[0][0][1] I am out of bounds, whereas I want a dimension 2 for the innermost vectors along the third dimension.

then I thought of this

[ [ [[] * 2] ]*3 ] * 10

I was thinking that [[] * 2] would now bring me the thing I want, an innermost two elements vector. I obtain

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

So, how to do it, or how to escape this initialization?

Kd rgds.

6 Answers 6

27

First of all, you should insert something into the innermost list (like None). Secondly, when you use the multiplication in the outermost list it replicates references to the inner list, so when you change one element, you will also change this element in all the other lists:

>> parameters = [ [ [None] * 2 ]*3 ] * 10
>> print parameters
[[[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]],
 [[None, None], [None, None], [None, None]]]
>> parameters[0][0][1]=1
>> print parameters 
[[[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]], [[None, 1], [None, 1], [None, 1]]]

Therefore, you should rather use list comprehensions:

>> parameters=[[[None for i in range(2)] for j in range(3)] for k in range(10)]

However, I would recommend to use numpy as suggested in one of the other answers.

Sign up to request clarification or add additional context in comments.

Comments

26

I would recommend you use Numpy for this kind of stuff. It makes accessing columns or rows much easier. For your use case you'd do

import numpy as np

matrix = np.zeros((2,3,10))
second_col = matrix[:,1,:]

Numpy will also take better care of your data, and it implements a lot of the matrix algebra in Fortran or C so it's going to be a lot faster in the (possible) future when you're doing matrix multiplication and the likes.

3 Comments

I am trying to create an index that roughly 40k x 40k. Would this have a massive mem foot print?
Assuming you're storing 64bit floats it'd be about 12GiB. If you're storing 8 but ints then it'd be 1/8th. You can you use scipy to create sparse matrices or numpy memory maps for on disk matrices
lol, thats correct. I have beefy servers at work, I generated a 40kx40k and it filled up 12 G in ram!! Thanks for other options.
8

Here's one of the problems with what you're doing.

Let's say you're creating an array, like so:

>>> l = [ [ [[] * 2] ]*3 ] * 10
>>> l
[[[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]], [[[]], [[]], [[]]]]

Seems okay so far. Let's set something in the array.

>>> l[0][0][0] = 2
>>> l
[[[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]], [[2], [2], [2]]]

Woah! We set 1 item in it, but it changed everything! How'd that happen?

Well, it appears that we have 60 list objects. However, we actually have 60 references to one list object. Change one, change them all.

TL;DR: Don't use the multiply operator on a list of lists.

Comments

6

I would do something like this, using this lists created are different objects (i.e different id()):

In [96]: [ [ [ []*2] for _ in range(3)] for _ in range(10) ]
Out[96]: 
[[[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]],
 [[[]], [[]], [[]]]]

In [98]: [id(x) for x in lis]   #all objects are unique
Out[98]: 
[151267948,
 151268076,
 151268492,
 151269164,
 151267276,
 151265356,
 151268140,
 151269036,
 151265644,
 151265964]


In [101]: lis1=[ [ [[] * 2] ]*3 ] * 10

In [102]: [id(x) for x in lis1]    # all objects are same, changing one will change 
                                   # others as well
Out[102]: 
[151278188,
 151278188,
 151278188,
 151278188,
 151278188,
 151278188,
 151278188,
 151278188,
 151278188,
 151278188]

Comments

2
# Creates an n x n matrix in p
n=int(input())
p=[[[] for x in range(1,10)]for x in range(1,10)]
print(p)

Comments

0

The correct way to do what you are trying to do is:

parameters = [ [ [[]] * 2 ]*3 ] * 10
parameters_mat = eval(str(parameters))

or, alternatively:

parameters = [ [ ['0'] * 2 ]*3 ] * 10
parameters_mat = eval(str(parameters))

In this way, you also solve the problem raised by @btel

1 Comment

What is the purpose of using eval here?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.