How to do pythonic list comprehensions with conditions in ruby? | One Big Library.
How to do pythonic list comprehensions with conditions in ruby? | One Big Library.
Somone was discussing this, I thought I’d post some examples:
I see the selects being written there attempting to operate on the variable. If this does do anything, it will be in-place on the array (or range) that you’re operating on. For an array, this is not really a problem, other than you probably didn’t want to do that:
[source:ruby]
>> a = (’a’..’z').to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
>> a.select do |l| l =~ /[aeiou]/ ? (l << ‘-mod’; l) : nil end
=> ["a-mod", "e-mod", "i-mod", "o-mod", "u-mod"]
>> a
=> ["a-mod", "b", "c", "d", "e-mod", "f", "g", "h", "i-mod", "j", "k", "l", "m", "n", "o-mod", "p", "q", "r", "s", "t", "u-mod", "v", "w", "x", "y", "z"]
[/source]
Obviously, you could make a copy of the array at this point, and it would solve the problem, at the obvious cost. See at the end for some examples of another way to achieve a similar effect in ‘one line’.
With a range, the outcome is different:
[source:ruby]
>> a = (’a’..’z')
=> “a”..”z”
>> a.select do |l| l =~ /[aeiou]/ ? (l << ‘-mod’; l) : nil end
=> ["a-mod"]
>> a
=> “a-mod”..”z”
[/source]
Why? because you’ve in-place modified the range. Now, what is an enumerator to do with a range, when you’ve modified it in-line? What is the next item from ‘a-mod’..’z’ from ‘a’?
‘a’ is no longer in the range.
If you want numeric iteration over a list, you first of all need a list!
[source:ruby]
>> r=[]; (’a’..’z').each {|v| r << v if v =~ /[aeiou]/}; r
=> ["a", "e", "i", "o", "u"]
>> y = []; for x in 0..10 do y << x * 3 if x % 2 == 0 end; y
=> [0, 6, 12, 18, 24, 30]
[/source]
The last ‘;var’ is only for irb to print the array we just created, you can remove it, or, if you really really want to, you could do this (might be suitable for a function)…
[source:ruby]
var = (y = []; for x in 0..10 do y << x * 3 if x % 2 == 0 end; y)
[/source]
There are some things in the ruby grammar I truly love, no matter how ‘useless’ they may seem.
None of this really offers you the pythonic syntax, but that’s not necessarily a bad thing.
The python syntax provides (in ruby terms) essentially two block passes. One before the for, and one after.
We can get closer to replicating this, but it still runs over the array twice (so the above solutions may be better), and the ordering of operation is different:
[source:ruby]
(0..10).select { |v| v % 2 == 0}.each {|v| v * 3}
[/source]
In comes inject…
[source:ruby]
>> (0..10).to_a.inject([]) do |a,x| a << x * 3 if x % 2 == 0; a end
=> [0, 6, 12, 18, 24, 30]
[/source]