Rails

【Rails】Ruby2.7.0から追加された「filter_mapメソッド」でコードをシンプルに

Rails

 

今回は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 }
可読性の賛否があること、ブロック変数の複雑さから上記では自動修正(Rubocop -A)は適用されていません。

 

こういったことから、今後は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]
even?は配列の中の偶数を判定するメソッドです。

参考: 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メソッドは、各要素に対してブロックを評価した値のうち、真であった値の配列を返す

参考

 

 

今回はRuby2.7.0から追加された「filter_mapメソッド」について解説しました。条件で絞り込んでブロックを評価するという実装は多く用いられるため、今後かなりお世話になりそうなメソッドな気がします。