はじめに
Rubyを学び始めてから、繰り返し処理にはかなり苦戦しました。
[1, 2, 3].each do |num|
puts num
end
これを最初に見たとき、正直「numって何者?」と思っていました。配列の中身と変数が繋がっているとは全然ピンと来ていなかったんです。
同じように「なんとなく動いてるけど、正直よくわかってない...」という方に向けて、自分が理解できたポイントを中心にまとめました。
納得できたポイント
オブジェクト と 変数 はイコールである
繰り返し処理の構文を見てみます。
# eachの場合
オブジェクト.each do |変数|
実行する処理
end
# forの場合
for 変数 in オブジェクト do
実行する処理
end
最初、この 変数(ブロック変数・一時変数とも呼ばれます)が何なのかわかりませんでした。
答えはシンプルです。「オブジェクトの要素が1つずつ入る入れ物」です。
[1, 2, 3].each do |num|
puts num
end
↓ こうイメージする
1回目: num = 1 → 1を表示
2回目: num = 2 → 2を表示
3回目: num = 3 → 3を表示
変数名は何でもOKです。numでもnでもitemでも、自分がわかりやすい名前にできます。
よく使う繰り返しメソッド
1. each ——基本中の基本
配列やハッシュの要素を1つずつ取り出して処理します。Rubyで繰り返しといえばまずこれ。
fruits = ["apple", "banana", "cherry"]
fruits.each do |fruit|
puts fruit
end
# apple
# banana
# cherry
do ... end の代わりに { } でも書けます(1行のときによく使われます)。
fruits.each { |fruit| puts fruit }
2. for ——見た目がわかりやすい
eachと同じことができますが、forの方が「日本語的な読み方」に近いかもしれません。
for fruit in fruits do
puts fruit
end
「fruitsの中からfruitを取り出して、処理する」と読めるので直感的です。
ただし、Rubyではfor文よりもeachの方が一般的によく使われます。
3. times ——回数指定ならこれ
「○回繰り返す」という場合は times が便利です。
3.times do
puts "Hello!"
end
# Hello!
# Hello!
# Hello!
何回目かも取得できます(0始まり)。
3.times do |i|
puts "#{i + 1}回目"
end
# 1回目
# 2回目
# 3回目
4. each_with_index ——インデックスも欲しいとき
eachだけでは「何番目の要素か」がわかりません。インデックスも使いたいときはこれ。
fruits = ["apple", "banana", "cherry"]
fruits.each_with_index do |fruit, index|
puts "#{index}: #{fruit}"
end
# 0: apple
# 1: banana
# 2: cherry
変数が2つ(fruitとindex)になります。
ちなみに
each.with_index(1)にすると1始まりにもできます。
fruits.each.with_index(1) do |fruit, index|
puts "#{index}: #{fruit}"
end
# 1: apple
# 2: banana
# 3: cherry
「戻り値」が変わる系のメソッド(ここから応用)
これが最初は特に混乱しました。eachは元の配列をそのまま返しますが、以下のメソッドは新しい配列を作って返します。
5. map ——全要素を変換して新しい配列を作る
numbers = [1, 2, 3, 4, 5]
doubled = numbers.map do |n|
n * 2
end
p doubled # [2, 4, 6, 8, 10]
eachとの違いは戻り値です。
# eachの戻り値 → 元の配列
result = [1, 2, 3].each { |n| n * 2 }
p result # [1, 2, 3] ← 変わらない!
# mapの戻り値 → 新しい配列
result = [1, 2, 3].map { |n| n * 2 }
p result # [2, 4, 6] ← 変換されている!
「each の中で n * 2 してるのに、なぜ結果が変わらないの?」と思うかもしれません。
each はブロック内で計算しても、その結果を捨てています。each の役割は「全要素を順番に処理すること」であって、「新しい値を集めること」ではないからです。
each の動き:
1 → n * 2 = 2 → ゴミ箱へ
2 → n * 2 = 4 → ゴミ箱へ
3 → n * 2 = 6 → ゴミ箱へ
最後に元の配列 [1, 2, 3] を返す
計算結果を使いたいなら puts で出力するか、map で受け取るかのどちらかです。
# 出力したいだけ → puts を使う
[1, 2, 3].each { |n| puts n * 2 }
# 2
# 4
# 6
# 新しい配列として受け取りたい → map を使う
result = [1, 2, 3].map { |n| n * 2 }
p result # [2, 4, 6]
each は「処理を流すだけ」、map は「処理結果を集める」と覚えると区別しやすいです。
ポイント:
mapはブロックの最後の評価値が新しい配列の要素になります。putsを書いてしまうと戻り値がnilになるので注意。
6. select ——条件に合う要素だけを取り出す
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = numbers.select do |n|
n.even? # 偶数かどうか
end
p even_numbers # [2, 4, 6]
selectはブロックの評価がtrueになった要素だけを集めた新しい配列を返します。
反対に、条件に合わない要素を取り出すrejectもあります。
odd_numbers = numbers.reject { |n| n.even? }
p odd_numbers # [1, 3, 5]
7. each_cons ——連続するN要素をまとめて処理
競技プログラミングやデータ処理でよく使います。最初見たときは何これ?ってなりましたが、意外と便利。
numbers = [1, 2, 3, 4, 5]
numbers.each_cons(3) do |group|
p group
end
# [1, 2, 3]
# [2, 3, 4]
# [3, 4, 5]
「3つの連続した要素をスライドしながら取り出す」イメージです。
繰り返しの制御
繰り返しの途中で抜けたり、スキップしたりする方法です。
| 命令 | 動作 |
|---|---|
break |
ループを途中で抜ける |
next |
今回の処理をスキップして次へ |
# break の例:2を見つけたらループを抜ける
[1, 2, 3].each do |n|
break if n == 2
puts n
end
# 1
# next の例:偶数はスキップ
[1, 2, 3, 4].each do |n|
next if n.even?
puts n
end
# 1
# 3
ハッシュの繰り返し
配列だけでなく、ハッシュにもeachが使えます。変数が2つになるのがポイント。
person = { name: "Taro", age: 25, city: "Tokyo" }
person.each do |key, value|
puts "#{key}: #{value}"
end
# name: Taro
# age: 25
# city: Tokyo
まとめ
| メソッド | 何をする? | 戻り値 |
|---|---|---|
each |
要素を1つずつ処理 | 元のオブジェクト |
for |
eachと同様(あまり使わない) | 元のオブジェクト |
times |
N回繰り返す | 繰り返し回数(Integer) |
each_with_index |
要素とインデックスを処理 | 元のオブジェクト |
map |
全要素を変換 | 新しい配列 |
select |
条件に合う要素を抽出 | 新しい配列 |
reject |
条件に合わない要素を抽出 | 新しい配列 |
each_cons(n) |
n個ずつ連続した要素を処理 | nil |
最初に each の「オブジェクトの要素が変数に1つずつ入る」というイメージを掴めると、他のメソッドも同じ発想で読めるようになります。
「なんとなく動いてる」から「なぜ動くかわかって使える」へのステップアップに、少しでもお役に立てたなら嬉しいです。
おまけ:この記事はAIと一緒に書きました
この記事は、ClaudeというAIのサポートを受けながら書きました。
具体的には、自分が「こういう内容を書きたい」「ここが苦手だった」という経験をざっくり伝えて、記事の構成や文章を一緒に作っていった感じです。
「eachの中でn * 2してるのに結果が変わらないのはなぜ?」という自分の疑問をそのままぶつけたら、ゴミ箱のたとえで説明してくれて、「これ記事にも入れよう」とそのまま追記したりもしました。
AIを使ったからといって手を抜いたわけではなく、自分が実際に詰まった経験・気づいたポイントが軸になっています。むしろ「自分の言葉で伝えたいこと」をAIが整理・肉付けしてくれるイメージで、アウトプットのハードルがかなり下がりました。
エンジニアの勉強でもAIをうまく使うのが当たり前になってきた時代なので、こういう使い方もありかなと思っています。