💡 この記事でわかること
eachだけでなく、配列に用意されている便利なメソッド(Enumerable)の存在map:各要素を変換した新しい配列を作る方法select・reject・find:条件で絞り込む・探す方法reduce(inject)で合計などを集計する方法、each_with_objectとの違いsort・uniq・sumなど、覚えておくと便利なメソッド一覧
1. 配列の便利メソッドとは?
配列の繰り返しというと、
👉 each で1つずつ処理する方法をすでに紹介しました。ですが実際のコードでは、each だけでなく「変換する」「絞り込む」「集計する」といった専用のメソッドがよく使われます。
これらのメソッドは Enumerable というしくみによって、配列(Array)やハッシュ(Hash)などに共通して用意されています。1つずつfor文で書くよりも、目的に合ったメソッドを使うほうが短く・読みやすいコードになります。
2. map ― 要素を変換した新しい配列を作る
map は、配列の各要素にブロックの処理を適用し、その結果を集めた新しい配列を返すメソッドです。
nums = [1, 2, 3, 4]
doubled = nums.map { |n| n * 2 }
p doubled # [2, 4, 6, 8]
p nums # [1, 2, 3, 4](元の配列は変わらない)👉 each は「処理をするだけ」で戻り値は元の配列のままですが、map は「変換した結果の配列」を返します。「新しい配列がほしいとき」は map、「表示するだけなど処理だけしたいとき」は each、と使い分けます。
💡 末尾に ! を付けた map! は、新しい配列を作らず元の配列そのものを書き換えます。破壊的メソッドと呼ばれ、意図せず元のデータを変えてしまう原因になりやすいので、まずは ! なしの map に慣れるのがおすすめです。
3. select・reject・find ― 条件で絞り込む・探す
select はブロックの条件が true になる要素だけを集めた配列を返します。reject はその逆で、条件が false の要素だけを集めます。
nums = [1, 2, 3, 4, 5, 6]
evens = nums.select { |n| n.even? }
p evens # [2, 4, 6]
odds = nums.reject { |n| n.even? }
p odds # [1, 3, 5]「条件に合う最初の1つだけ」がほしいときは find(別名 detect)を使います。見つからなければ nil が返ります。
nums = [1, 2, 3, 4, 5, 6]
first_even = nums.find { |n| n.even? }
p first_even # 24. reduce(inject) ― 集計する
reduce(別名 inject)は、配列の要素を1つにまとめて集計するメソッドです。合計・最大値など「畳み込み」の処理に使います。
nums = [1, 2, 3, 4]
total = nums.reduce(0) { |sum, n| sum + n }
p total # 10
# 初期値を省略すると、最初の要素が初期値になる
total2 = nums.reduce { |sum, n| sum + n }
p total2 # 10
# 記号だけでも書ける(よく見る書き方)
total3 = nums.reduce(:+)
p total3 # 10reduce のブロックには「それまでの集計結果(sum)」と「今見ている要素(n)」が渡され、ブロックの戻り値が次の回の sum になります。
💡 ブロックの最後に sum + n のような「次に渡す値」を書き忘れると、集計結果がおかしくなります(たとえば途中で puts だけ書いて終えると、sum が nil になってしまいます)。reduce は「ブロックの戻り値がそのまま次の引数になる」という点を意識して使いましょう。
👉 戻り値の考え方(メソッドの最後に評価した式が返る)についての記事はこちら
5. each_with_object ― 集計用オブジェクトを組み立てる
reduce は数値の合計のような「1つの値」を作るのは得意ですが、配列やハッシュを組み立てていく場合は each_with_object のほうが書きやすいことがあります。ブロックの戻り値を意識しなくてよいのが特徴です。
words = ["apple", "banana", "fig"]
# 単語ごとの文字数を、ハッシュに集めていく
lengths = words.each_with_object({}) do |word, hash|
hash[word] = word.length
end
p lengths # {"apple"=>5, "banana"=>6, "fig"=>3}👉 each_with_object(初期値) に渡した初期値(ここでは {})がブロックに渡され、それを毎回書き換えていくだけでよく、最後に each_with_object 自身がその初期値を返してくれます。reduce のように「次に渡す値を毎回returnする」必要がないぶん、配列やハッシュを組み立てるときはこちらのほうが直感的です。
6. sort・sort_by ― 並べ替える
sort は要素を並べ替えた新しい配列を返します。数値や文字列はそのまま昇順に並びます。
nums = [3, 1, 4, 1, 5]
p nums.sort # [1, 1, 3, 4, 5]
p nums.sort { |a, b| b <=> a } # [5, 4, 3, 1, 1](降順)ハッシュの配列など「何を基準に並べるか」を指定したいときは sort_by が便利です。ブロックで「並び替えの基準にする値」を返すだけで、比較のしかたを自分で書く必要がありません。
users = [
{ name: "太郎", age: 25 },
{ name: "花子", age: 20 },
{ name: "次郎", age: 30 }
]
by_age = users.sort_by { |user| user[:age] }
p by_age.map { |user| user[:name] } # ["花子", "太郎", "次郎"]👉 sort { |a, b| ... } は2つの要素を比較する式(<=>)を自分で書く必要がありますが、sort_by { |x| ... } は「基準になる値」を返すだけで済みます。降順にしたい場合は sort_by { |user| -user[:age] } のようにマイナスを付けるのが定番です。
7. その他よく使うメソッド
ここまでのほかにも、覚えておくと便利なメソッドがあります。
nums = [3, 1, 2, 2, 3]
p nums.uniq # [3, 1, 2](重複を取り除く)
p nums.sum # 11(合計)
p nums.min # 1
p nums.max # 3
p nums.count { |n| n.odd? } # 3(条件に合う個数)
nested = [[1, 2], [3, 4]]
p nested.flatten # [1, 2, 3, 4](配列の入れ子を平らにする)👉 「配列に対してやりたいこと」から逆引きでメソッド名を覚えていくのがおすすめです。すべてを暗記する必要はなく、「変換なら map、絞り込みなら select」という大まかな対応が頭に入っていれば、あとは調べながら書けます。
8. メソッドチェーンで組み合わせる
これらのメソッドは、. でつなげて組み合わせる(メソッドチェーン)ことができます。「絞り込んでから変換する」といった処理も1行で書けます。
nums = [1, 2, 3, 4, 5, 6]
# 偶数だけを2倍にした配列
result = nums.select { |n| n.even? }.map { |n| n * 2 }
p result # [4, 8, 12]👉 1つ前のメソッドが返した配列に対して、次のメソッドが実行されます。長くつなげすぎると読みにくくなるので、最初は2〜3個までを目安に組み合わせるとよいでしょう。
9. 配列メソッド 早見表
| メソッド | やること |
|---|---|
each | 1つずつ処理する(戻り値は元の配列) |
map | 各要素を変換した新しい配列を作る |
select / reject | 条件に合う / 合わない要素を集める |
find | 条件に合う最初の1つを探す(なければ nil) |
reduce(inject) | 集計して1つの値にまとめる |
each_with_object | 配列・ハッシュを組み立てながら集計する |
sort / sort_by | 並べ替える |
uniq / flatten | 重複を除く / 入れ子を平らにする |
sum / min / max / count | 合計・最小・最大・件数を求める |
10. まとめ
- 配列には
eachのほかに、変換・絞り込み・集計のための便利なメソッド(Enumerable)が用意されている mapは変換、select・reject・findは絞り込み・検索に使うreduceは集計に便利だが、ブロックの戻り値が次の値になる点に注意。組み立てならeach_with_objectも選択肢- 並べ替えは
sort/sort_by、そのほかuniq・sumなども覚えておくと便利 - メソッドは
.でつなげて組み合わせられる(メソッドチェーン)
👉 最初から全部を覚えようとせず、まずは map と select の2つから使ってみましょう。この2つだけでも、for文を書くよりずっとすっきりしたコードになります。慣れてきたら reduce や sort_by を試してみてください。