From: jon@... Date: 2020-06-25T18:23:37+00:00 Subject: [ruby-core:98939] [Ruby master Feature#16147] List Comprehensions in Ruby Issue #16147 has been updated by emptyflask (Jon Roberts). In my opinion, the more useful types of list comprehensions are when multiple inputs are needed. The Ruby syntax in example one looks best, but requires more array manipulation, even if Enumerable#filter_map replaces select.map. Example four is the kind of method we should be comparing with list comps. ``` ruby # Nice syntax, but slow: def one(a,b,c) a.product(b, c) .select {|x, y, z| x < y && y > z } .map(&:sum) end # Combine select and map in Ruby 2.7 def two(a,b,c) a.product(b, c) .filter_map {|x, y, z| x+y+z if x < y && y > z } end # Ugly but more efficient, requires a mutable result array: def three(a,b,c) res = [] a.product(b, c) do |x, y, z| res << x+y+z if x < y && y > z end res end # About the same performance as three, slightly cleaner: def four(a,b,c) [].tap do |res| a.product(b, c) do |x, y, z| res << x+y+z if x < y && y > z end end end # user system total real # 1.566321 0.100999 1.667320 ( 1.667341) # 0.884384 0.016958 0.901342 ( 0.901343) # 0.708852 0.005994 0.714846 ( 0.714862) # 0.714095 0.000005 0.714100 ( 0.714138) ``` ``` -- List comprehension (Haskell syntax): five a b c = [ x+y+z | x <- a, y <- b, z <- c, x < y, y > z ] ``` ---------------------------------------- Feature #16147: List Comprehensions in Ruby https://bugs.ruby-lang.org/issues/16147#change-86313 * Author: sammomichael (Samuel Michael) * Status: Open * Priority: Normal ---------------------------------------- ## List comprehensions are present in many languages and programmers are quite fond of their simplicity and power. Add to that the fact that Ruby has a for...in loop that is rarely used but could possibly be repurposed. ### Currently we can already do a hack like this to make Ruby support list comprehension syntax: ``` ruby S = [for x in 0...9 do $* << x*2 if x.even? end, $*][1] # [0, 4, 8, 12, 16] ``` Still, it would be far nicer if the for...in loop would return the desired array automatically, this is one way to approach that taking advantage of lambda bracket invocation syntax: ``` ruby c = -> x do $*.clear if x['if'] && x[0] != 'f' . y = x[0...x.index('for')] x = x[x.index('for')..-1] (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}") x.insert(x.length, "end; $*") eval(x) $*) elsif x['if'] && x[0] == 'f' (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << x") x.insert(x.length, "end; $*") eval(x) $*) elsif !x['if'] && x[0] != 'f' y = x[0...x.index('for')] x = x[x.index('for')..-1] (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}") x.insert(x.length, "end; $*") eval(x) $*) else eval(x.split[3]).to_a end end ``` so basically we are converting a string to proper ruby syntax for loop then we can use python syntax in a string to do: ``` ruby c['for x in 1..10'] c['for x in 1..10 if x.even?'] c['x**2 for x in 1..10 if x.even?'] c['x**2 for x in 1..10'] # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # [2, 4, 6, 8, 10] # [4, 16, 36, 64, 100] # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] ``` -- https://bugs.ruby-lang.org/ Unsubscribe: