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