RAS Syndrome

冗長。

Ruby のリスト操作メソッド使い分け指針

なかなかリスト操作に慣れない初心者のために、よく使うメソッドを抜粋し、「どういう時に使うか」をすごい雑な言葉で添えながら列挙してみる。

なお、リストとか配列とか Enumerable とか、この辺の言葉の使い分けはよく分かんないので、とりあえず全部「リスト」と呼ぶことにする。

ちなみに、執筆時点での Ruby のバージョンは 2.6 である。

参考: docs.ruby-lang.org

docs.ruby-lang.org

使い分け

  • 操作対象リストと同じ要素数のリストが欲しい
    • 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)と「出力」(副作用)は別々の行為なので、分けた方が理念としては自然。