each は配列を変換しない(map との違い)
eachブロックの中で要素を加工しても、eachの戻り値はレシーバ自身(変更前の配列)のままです。加工した結果からなる新しい配列が欲しい場合はmapを使う必要があります。
なぜエラーが出ないのか
出力: [1, 2, 3]
(エラーなし)- Rubyは何も報告しません。文法として正しいためです
出力: [1, 2, 3]- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 nums = [1, 2, 3] 2 doubled = nums.each { |n| n * 2 } ^ 3 puts doubled.inspect
出力: [1, 2, 3]
eachはブロックの中で何を計算しても、戻り値は常に元の配列自身です。変換結果の配列が欲しい場合はmapを使います。
直し方: each を map にします。
広告
広告スロット(未設定)
パターン2
1 prices = [100, 200, 300] 2 taxed = prices.each { |p| (p * 1.1).round } ^ 3 puts taxed.inspect
出力: [100, 200, 300]
eachブロックの中の計算結果は捨てられ、doubledには変更前の配列がそのまま入ります。
直し方: each を map にします。
パターン3
1 names = ["taro", "hanako"] 2 upcased = names.each { |n| n.upcase } ^ 3 puts upcased.inspect
出力: ["taro", "hanako"]
文字列を大文字化した「つもり」でも、eachでは元の配列が変わらないまま返ってきます。
直し方: each を map にします。
パターン4
1 scores = [60, 70, 80] 2 bonused = scores.each { |s| s + 10 } ^ 3 puts bonused.inspect
出力: [60, 70, 80]
加算した結果を集めた新しい配列が欲しいなら、eachをmapに置き換える必要があります。
直し方: each を map にします。
パターン5
1 words = ["cat", "dog"] 2 lengths = words.each { |w| w.length } ^ 3 puts lengths.inspect
出力: ["cat", "dog"]
エラーは出ないため、出力を確認するまでeachとmapの取り違えには気づけません。
直し方: each を map にします。
よくある誤解
「eachブロックの中で計算した結果が、そのままeachの戻り値になるはず」という思い込みは誤りです。eachは常に元の配列自身を返すため、変換結果を集めたいならmapに置き換える必要があります。
まとめ
each は配列を変換しない(map との違い)は初級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。