Hi,

2011/11/23 Yehuda Katz <wycats / gmail.com>:
> 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