From: Shugo Maeda Date: 2011-11-23T07:26:18+09:00 Subject: [ruby-core:41222] Re: [ruby-trunk - Bug #5663][Open] Combined map/select method Hi, 2011/11/23 Yehuda Katz : > It is pretty common to want to map over an Enumerable, but only include the elements that match a particular filter. A common idiom is: > > enum.map { |i| i + 1 if i.even? }.compact > > It is of course also possible to do this with two calls: > > enum.select { |i| i.even? }.map { |i| i + 1 } > > Both cases are clumsy and require two iterations through the loop. I'd like to propose a combined method: > > enum.map_select { |i| i + 1 if i.even? } > > The only caveat is that it would be impossible to intentionally return nil here; suggestions welcome. The naming is also a strawman; feel free to propose something better. How about to add list comprehensions or Scala's for expressions instead? For example, enum.select { |i| i.even? }.map { |i| i + 1 } can be written as follows: [ i + 1 for i in enum if i.even? ] # The syntax of list comprehensions needs more considerations. One benefit is that nested maps can be flattened by list comprehensions. For example, the following code: pyths = [ [x, y, z] for z in [1..Float::INFINITY].defer x in [1..z].defer y in [x..z].defer if x**2 + y**2 == z**2 ] p pyths.take(3) is equivalent to the following code: pyths = (1..Float::INFINITY).defer.flat_map {|z| (1..z).defer.flat_map {|x| (x..z).defer.select {|y| x**2 + y**2 == z**2 }.map {|y| [x, y, z] } } } p pyths.take(3) # Enumerable#defer is proposed in Feature #4890. BTW, now Ruby has map and reduce as aliases of collect and inject, but not filter as an alias of select. Why not? -- Shugo Maeda