今回はRuby2.7.0から追加された「filter_mapメソッド」について解説したいと思います。filterメソッド(selectメソッド)とmapメソッド(collectメソッド)をチェーンさせて記述していた箇所は、今後はfilter_mapに置き換えるようにしましょう。
Rubocop対応が行われた話
2021/04/22にRuboCop Performance 1.11がリリースされ、新たなCopが追加されました。それが「filter_mapメソッド」になります。
これまでselectメソッドとmapメソッドをメソッドチェーン的に繋げて記述することも可能でしたが、今回のリリースでそれらはBadケースになります。
# 悪い例
ary.select(&:foo).map(&:bar)
ary.filter(&:foo).map(&:bar)
# 良い例
ary.filter_map { |o| o.bar if o.foo }
こういったことから、今後はfilter_mapの使用が推奨されていることが分かりますね。
filter_mapメソッドの使用例
では続いてfilter_mapメソッドの使用例を見ていきましょう。
メソッド名の通りですが、filter_mapメソッドはfilterメソッドとmapメソッドの組み合わせであるため、それぞれのメソッドについて理解しておく必要があります。
filterメソッド(selectメソッド)
filterメソッド(selectメソッド)は、各要素に対してブロックを評価した値が真であった要素を全て含む配列を返します。真になる要素がひとつもなかった場合は空の配列を返します。
[1,2,3,4,5].filter { |num| num.even? } # => [2, 4]
参考: instance method Array#filter
mapメソッド(collectメソッド)
mapメソッド(collectメソッド)は、各要素に対してブロックを評価した結果を全て含む配列を返します。ブロックを省略した場合、上で説明した繰り返しを実行し、その結果として得られる配列を返すような Enumerator オブジェクトを返します。
p (1..3).map {|n| n * 3 } # => [3, 6, 9]
p (1..3).map { "cat" } # => ["cat", "cat", "cat"]
参考: instance method Enumerable#collect
filter_mapメソッド
上記を踏まえてfilter_mapメソッドについて見ていきます。
filter_mapメソッドは、各要素に対してブロックを評価した値のうち、真であった値の配列を返します。条件の絞り込みとブロックの評価を同時に行えるメソッドになりますね。
(1..10).filter_map { |i| i * 2 if i.even? } #=> [4, 8, 12, 16, 20]
[1,2,3,4].filter_map { |i| i * 2 if i > 1 } #=> [4, 6, 8]
参考: instance method Enumerable#filter_map
まとめ
- RuboCop Performance 1.11では「filter_mapメソッド」がCopに追加された
- filterメソッド(selectメソッド)は、各要素に対してブロックを評価した値が真であった要素を全て含む配列を返す
- mapメソッド(collectメソッド)は、各要素に対してブロックを評価した結果を全て含む配列を返す
- filter_mapメソッドは、各要素に対してブロックを評価した値のうち、真であった値の配列を返す
参考
- RuboCop Performance 1.11 をリリースした
- instance method Array#filter
- instance method Enumerable#collect
- instance method Enumerable#filter_map
今回はRuby2.7.0から追加された「filter_mapメソッド」について解説しました。条件で絞り込んでブロックを評価するという実装は多く用いられるため、今後かなりお世話になりそうなメソッドな気がします。