Ruby のリスト操作メソッド使い分け指針
なかなかリスト操作に慣れない初心者のために、よく使うメソッドを抜粋し、「どういう時に使うか」をすごい雑な言葉で添えながら列挙してみる。
なお、リストとか配列とか Enumerable とか、この辺の言葉の使い分けはよく分かんないので、とりあえず全部「リスト」と呼ぶことにする。
ちなみに、執筆時点での Ruby のバージョンは 2.6 である。
使い分け
- 操作対象リストと同じ要素数のリストが欲しい
Enumerable#map
(collect
)
- 操作対象リストより要素数の少ないリストが欲しい
- 条件が当てはまる要素だけを抽出
Enumerable#find_all
(select
,filter
)
- 特に、nil じゃない要素だけを抽出
Array#compact
- 先頭から条件が当てはまらなくなるまでスライス
Enumerable#take_while
- 先頭から N 個
Enumerable#take
- 重複排除
Enumerable#uniq
- 条件が当てはまる要素だけを抽出
- 操作対象リストの中から 1 個抽出
- 条件に当てはまる最初のやつ
Enumerable#find
(detect
)
- 最初のやつ
Enumerable#first
- 最後のやつ
Array#last
- N 番目
Array#[]
Array#fetch
- 最大最小
Enumerable#max
(<->min
)Enumerable#max_by
(<->min_by
)
- 条件に当てはまる最初のやつ
- Bool 値が欲しい
- 要素があるかどうか
Enumerable#member?
(include?
)
- 条件を満たす要素があるかどうか
Enumerable#any?
- 全要素が条件を満たすかどうか
Enumerable#all?
(<->none?
)
- 要素があるかどうか
- 要素数が欲しい
- 全要素の数
Enumerable#count
Array#length
(size
)
- 条件を満たす要素の数
Enumerable#count
- 全要素の数
- 集計値が欲しい
- 和
Enumerable#sum
- その他なんでも
Enumerable#reduce
- 和
- 良いメソッドがないけど、とにかく全要素をイテレートしながら何かの値を得たい
Enumerable#reduce
Enumerable#each_with_object
- 何も欲しくなくて、ただ副作用だけを各要素に行いたい
Enumerable#each
特に map はよく使う
リストに Enumerable#map
して得られる結果もまたリストであるため、他のリスト操作を組み合わせて使うことも非常に多い。
例:
# 名前の最大文字数を調べる max_length = ['Alice', 'Bob', 'CaptainFalcon'].map(&:length).max puts max_length # -> 13
複雑なリスト操作の組み合わせが必要そうだと思った時は、「どんなリストに変換していけば良いだろうか」って考え方をすると捗るかもしれない。
※ &:length
の意味はこちらを参照。
ref.xaio.jp
each は最小限に
副作用はなるべく切り離す。
悪い例:
# 整数の 2 乗を出力 (1..5).each { |num| puts num**2 }
良い例:
(1..5).map { |num| num**2 } # 整数の 2 乗 .each { |num| puts num } # 出力
理由
副作用のない部分(例でいうところの「整数の 2 乗を取り出す」)はテストがしやすい。テストしやすい部分が多いと嬉しい。
こんなしょぼいサンプルだとデメリットの方が大きく見えるかもしれないけど、まあ理念としてね。
「変換」(map
)と「出力」(副作用)は別々の行為なので、分けた方が理念としては自然。