Hacker News new | comments | ask | show | jobs | submit login

My biggest issue with list comprehensions is that while it's a useful and fairly readable format for a single list comprehension, either little attention was given to how it would function when taking a comprehension of of comprehension, or they thought the syntax would be so cumbersome people wouldn't do so (ha!).

When compared to a set of functional style mapping and filtering functions, it quickly becomes much less readable as your needs become anything more than trivial. My main issue is that focus for the important aspect of what is being accomplished swings back and forth from the front to the back of the statement multiple times, especially if nested and with conditionals. e.g.

  [(x,y) for x in range(10) for y in range(10) if y > 5 if x < 6]
or, in a similar formatting to what you show:

  [
    (x,y)
    for x in range(10)
      for y in range(10)
      if y > 5
    if x < 6
  ]
In both cases, the accurate reading requires scanning back and forth from beginning to end of statement (whether vertically or horizontally) because the conditionals always postfix the rest of it (and this example is not as complex as it could be). For loops would likely have the conditionals preceding everything, making it obvious, and a set of filtering statements. The functional style also allows for a fairly straightforward reading of what's going on:

  toTen.filter(y=>y>5).flatMap(y=> toTen.filter(x=>x<6).map(x=>[x,y]) );
or:

  toTen.filter(y=>y>5).flatMap(y =>
    toTen.filter(x=>x<6).map(x=>
      [x,y]
    )
  );
Of course the functional style does require at least some minimal knowledge of some concepts often extraneous to novice programmers, so I understand why that wasn't chosen in Python's case. I just wish they had put conditionals in the same positional flow as the rest of the statement.



That's not quite right. The conditionals are executed in order in the innermost loop. For instance:

  >>> [(x,y) for x in range(2) for y in range(2) if print(x, y) is None if print(x, y) is None]
  0 0
  0 0
  0 1
  0 1
  1 0
  1 0
  1 1
  1 1
  [(0, 0), (0, 1), (1, 0), (1, 1)]
Both conditionals have access to x and y.

So the list comprehension is equivalent to this:

  [(x,y) for x in range(10) for y in range(10) if y > 5 and x < 6]
And could more clearly be formatted like this:

  [
    (x,y)
    for x in range(10)
      for y in range(10)
        if y > 5
          if x < 6
  ]
And would look something like this in a functional style, perhaps:

  toTen.flatMap(x =>
    toTen.filter(x => x<6 && y>5).map(y=>
      [x,y]
    )
  );


Ah, thanks for the clarification. Python is not a language I use often (but of course is a language seen often).

I actually see what's going on a bit clearer now, as I looked closer and found that the correct way to write what I was originally trying to express is actually:

   [(x,y) for x in range(10) if x < 6 for y in range(10) if y > 5]
which could be formatted as:

  [
    (x,y)
    for x in range(10)
      if x < 6
        for y in range(10)
          if y > 5
  ]
Which is actually much closer to the functional style's flow, and is correctly eliminating iterations earlier in the loop (which is an important consideration).

I was confused because I had seen examples where multiple if clauses where added to the right side, one per loop level (as I showed), and that makes it look like they are operating on the different levels, when in reality they are working on the innermost loop, like you showed.

I'll retract most my complaints then. There's still some question in my mind as to how you would usefully mutate items of the loop and use them in other levels of the loop without recomputing them again, but that might just be my unfamiliarity with the construct.


I agree. The most readable syntax for sequence comprehensions that I know of is C# LINQ and XQuery FLWOR, and it's no coincidence that they put the projection clause ("select" in C#, "return" in XQuery) last - it follows the overall flow better.




Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: