The nested list:
In [14]: [[j for i in range(3)] for j in range(4)]
Out[14]: [[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]]
The "stacking" is just a display issue. This is a list of lists; whether they are displayed on one line or separately is just display choice. The underlying data structure is the same.
better, yet let's use the i
as well (not just a iteration count):
In [16]: [[(j,i) for i in range(3)] for j in range(4)]
Out[16]:
[[(0, 0), (0, 1), (0, 2)],
[(1, 0), (1, 1), (1, 2)],
[(2, 0), (2, 1), (2, 2)],
[(3, 0), (3, 1), (3, 2)]]
(here they are "stacked" because the sublists are longer; it's been 'pretty printed'.
The outer list has 4 elements (range 4), the inner ones 3 (plus the tuple inside.
Or we could combine the indices and make an array from the nested list:
In [17]: [[i*j for i in range(3)] for j in range(4)]
Out[17]: [[0, 0, 0], [0, 1, 2], [0, 2, 4], [0, 3, 6]]
In [18]: np.array(_)
Out[18]:
array([[0, 0, 0],
[0, 1, 2],
[0, 2, 4],
[0, 3, 6]])
But in numpy
we prefer to build a 2d array from a combination of 1ds
In [19]: np.arange(4)[:,None] * np.arange(3)
Out[19]:
array([[0, 0, 0],
[0, 1, 2],
[0, 2, 4],
[0, 3, 6]])
But if you just want 0s, use
In [20]: np.zeros((4,3), dtype=int)
Out[20]:
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
The nested list comprehension is just a compact expression of two for loops:
In [21]: alist = []
In [22]: for j in range(4):
...: blist = []
...: for i in range(3):
...: blist.append(f'{j}:{i}')
...: alist.append(blist)
...:
In [23]: alist
Out[23]:
[['0:0', '0:1', '0:2'],
['1:0', '1:1', '1:2'],
['2:0', '2:1', '2:2'],
['3:0', '3:1', '3:2']]