5 ms·
Before Ruby introduced filter_map: res = (1..10).select { |x| x != 5 }.map { |x| x ** 2 } With filter_map: res = (1..10).filter_map { |x| x ** 2 if x != 5 }
by michaelteter 4y ago
Before Ruby introduced filter_map:
res = (1..10).select { |x| x != 5 }.map { |x| x ** 2 }
With filter_map:
res = (1..10).filter_map { |x| x ** 2 if x != 5 }
In both cases, I think the Ruby solution is more readable.
Python list comprehensions invert the subject (data) and the verb (action). You see what will be done before you see what the subject is. I would argue that showing the subject first allows easier code review as you know immediately what you are working with.
But beyond that, the first Ruby example tells you in English what is happening. "take this range", "select a subset", then "map some actions to the elements".
And the filter_map abbreviation does the same, telling you "take this range, filter it and perform an operation on the remaining elements".
Python tells you nothing... and what it does say is in awkward order.
As functional and data-oriented programming is gaining in popularity (for good reason), adopting some functional practices in Ruby is a pleasant experience. Doing the same in Python exposes more of these... irregularities.
Edit - I always forget how to format symbols in these comments!
- nuker 4y ago> In both cases, I think the Ruby solution is more readable. Nope.
- robertlagrant 4y agoThe Python one looks fine to me, although I am a Pythonish person. It uses what people already know: the for something in somethings syntax of the for loop, and the if syntax. Also it's nice that this works in dictionaries, generators and lists. It also has the same narrative flow of Haskell's list comprehensions, which I think come from set theory: [x^2 | x <- [0..10], x `mod` 5 /= 0] As for your Ruby examples: I think you could argue that the filter_map version is very readable, but not necessarily more so, but the select one looks pretty painful.
- deleted 4y ago[deleted]
- petre 4y ago> As for your Ruby examples: I think you could argue that the filter_map version is very readable, but not necessarily more so, but the select one looks pretty painful. The select does two passes, which makes it quite inefficient. One does not even need filter_map, since the example is essentially a reduce operation. res = (1..10).reduce([]) { |a, x| x != 5 ? a.push(x**2) : a } This works in ruby 2.5.1. Probably works in 1.9 and mruby as well.
- robertlagrant 4y agoTrue, although that seems less readable than the comprehension versions. I might be just biased, though.
- zem 4y agoyou can define pretty much everything as a reduce operation though
- empthought 4y ago> I think the Ruby solution is more readable. I disagree and I’ve used both professionally for about the same amount of code.
- nickjj 4y agoI think this is purely a personal preference but I also think there is a bias towards list comprehensions being more difficult to mentally parse. I do a lot of contract work and chatted with a ton of folks ranging from beginners to veterans. A lot of them (well more than half) avoid list compressions, especially when working with teams because it's such a mixed bag of either being able to instantly understand them or it requires more effort. Personally I don't use them in my code (for both reasons). Both Ruby solutions are much more clear to me even though I have no functional programming background. I have no preference towards functional styles either, I would say it's the opposite. I struggled with Elixir long enough that I stopped using it.
- empthought 4y agoI disagree about list comprehensions, as do more than half the people I’ve asked over the years.
- eternalban 4y agoI don’t use either, and also have an admittedly irrational dislike for Python. That said, the Python variant is more readable imo as well.
- michaelteter 4y agoAnd yet, in the production Python codebases I've worked with, list comprehensions are rarely seen. Usually it's typical loop iterations. I wonder why that is?...
- deleted 4y ago[deleted]
- empthought 4y ago
- nequo 4y agoThis may be a nitpick but Ruby’s naming seems inconsistent. If `filter_map` combines `select` and `map`, why is it not called `select_map`?
- robertlagrant 4y agoThinking further about this, how does this work with multiple loops? E.g. [x + y for x in range(10) for y in range(5)]