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.

kiriloff
  • 25,609
  • 37
  • 148
  • 229

6 Answers6

25

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.

Community
  • 1
  • 1
Matti Lyra
  • 12,828
  • 8
  • 49
  • 67
  • I am trying to create an index that roughly 40k x 40k. Would this have a massive mem foot print? – ScipioAfricanus Mar 08 '19 at 21:27
  • 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 – Matti Lyra Mar 09 '19 at 11:26
  • 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. – ScipioAfricanus Mar 09 '19 at 16:05
24

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.

btel
  • 5,563
  • 6
  • 37
  • 47
7

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.

Nick ODell
  • 15,465
  • 3
  • 32
  • 66
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]
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
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)
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

Pezz
  • 51
  • 1
  • 6