0

I'm practicing list comprehension techniques and I'm a bit confused about this one.

arr1 = np.array([[j for i in range(10)] for j in range(10)])

So I understand that you want a number j for every i in range(10), which sort of doesn't make sense cause you didn't initialize j, so it should be i for i in range(10). Then we somehow initialize 10 columns, but how does the left j relate to the j in range(10)?

Pretty confused about this, I would really appreciate it if someone could translate this to what is actually going on.

Also, in Java you initialize 2d arrays like so: int[][] arr1 = new int[5][2]; // 5 rows, 2 columns, could you achieve this in python without list comprehension?

JakoSA12
  • 13
  • 1
  • 5
  • Don't do that. List comprehensions sacrifice the benefits of NumPy. – user2357112 Sep 15 '20 at 23:32
  • If you just want an x-by-y array, use `numpy.zeros`. – user2357112 Sep 15 '20 at 23:33
  • I sort of have to understand it though, our lecturer uses these. – JakoSA12 Sep 15 '20 at 23:34
  • For a start omit the `np.array` part, and focus on comprehension itself. Look at the nested list it produces. That's basic python. – hpaulj Sep 15 '20 at 23:39
  • @hpaulj yeah, it's supposed to be an intro to python. I've removed the numpy part and I can see now that `arr1 = [[j for i in range(10)] for j in range(3)]` prints out a list of lists, 3 arrays, 10 columns each (basically the same as with numpy, but the rows are not stacked up) . But it still doesn't help me understand how the list comprehension actually works. – JakoSA12 Sep 15 '20 at 23:44
  • In python, you can't declare a fixed-size array. To get functionality similar to the Java syntax using `numpy`, though, you could use https://stackoverflow.com/a/20613451/5748696 – shynjax287 Sep 15 '20 at 23:44
  • The `for j in range(3)` is the outer loop, so that's why the result list has 3 sub-lists. The `j for i in range(10)` creates 10 entries in each sub-list, since it is in the inner scope. This may be useful: https://stackoverflow.com/a/45079294/5748696 – shynjax287 Sep 15 '20 at 23:46
  • 3
    Does this answer your question? [List comprehension on a nested list?](https://stackoverflow.com/questions/18072759/list-comprehension-on-a-nested-list) – shynjax287 Sep 15 '20 at 23:47

1 Answers1

5

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']]
hpaulj
  • 221,503
  • 14
  • 230
  • 353