4

I got absolutely stumped at:

indices = numpy.array([b for a in x for b in a if not b==k])

Any pointers on how I should read [b for a in x for b in a if not b==k], in the context of x being a 2D-array of integers and k being an integer? Or parenthesize it to help me understand the precedence of things?

Dan
  • 9,912
  • 18
  • 49
  • 70
  • 2
    Possible duplicate of [python list comprehension double for](http://stackoverflow.com/questions/17657720/python-list-comprehension-double-for) – Stefan Pochmann Mar 04 '17 at 22:22
  • Thank you, @StefanPochmann. I'm so new to Python I didn't have the proper vocabulary to search for duplicates. – Dan Mar 04 '17 at 22:24

2 Answers2

7

This is equivalent to:

result = []
for a in x:
    for b in a:
        if not b == k:
            result.append(b)
indices = numpy.array(result)

You can read the list comprehension from left to write and turn them into separate for loops.

Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
2

It flattens one dimensions of the x array (I think the code assumes x is a 2D array) and removes every occurence of the integer k. For example:

>>> import numpy as np

>>> x = np.arange(20).reshape(4, 5)  # makes it a 2D array
>>> x
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])
>>> k = 4

>>> inds = np.array([b for a in x for b in a if not b==k])
>>> inds
array([ 0,  1,  2,  3,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])

Note that your code isn't really using the powerful and fast NumPy functionality. If x is an array you could simply use:

>>> x[x!=k]  # make it 1D and keep only values != k
array([ 0,  1,  2,  3,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • This order really doesn't make sense to me. It feels like german numbers : `123` is `hundred three and twenty`. I'd expect `[b for b in a for a in x if not b==k]` – Eric Duminil Mar 04 '17 at 22:31
  • @EricDuminil A list-comprehension has the same structure as if you've written it as real `for-loops`. First comes the outer loop `for a in x`, then the inner `for b in a`. – MSeifert Mar 04 '17 at 22:34
  • Yes. It's readable with newlines and indentation, it's not readable IMHO when written on one line. You cannot read it as a sentence, and it's harder to parse. – Eric Duminil Mar 04 '17 at 22:36
  • Also, the documentation [example](https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions) is kinda useless because it uses independent variables. `x` and `y` could be swapped. – Eric Duminil Mar 04 '17 at 22:38
  • 1
    @EricDuminil Well, unfortuntaly the OP didn't use newlines in the comprehension. I also think it's not so readable. However there is always `itertools.chain` which makes the double-loop mostly unnecessary: `[item for item in itertools.chain.from_iterable(x) if item != k]`. But if one is using `NumPy` the `x[x!=k]` is even better. :) – MSeifert Mar 04 '17 at 22:39
  • 1
    @EricDuminil It also looks weird if one is using newlines... https://gist.github.com/MSeifert04/54ec072097441d5a8ebc33967f632a97 :) – MSeifert Mar 04 '17 at 22:44
  • 1
    I was more complaining about this Python syntax design than about OP's code. But thanks for your comments. Anyway, I'm just nitpicking. Coming from Ruby, list comprehensions are refreshing, but double comprehensions could have been more beautiful IMHO. With newlines, I was talking about the classic for loops. Comprehensions with newlines look weird indeed. – Eric Duminil Mar 04 '17 at 22:46
  • let me just add that this is my _first_ experience with Python, so you can imagine jumping right into what I now understand is called double comprehension :) thank you again for clearing this up for me. – Dan Mar 04 '17 at 22:49