hash = { "d" => [11, 22], "f" => [33, 44, 55] }
# case 1
hash.map {|k,vs| vs.map {|v| "#{k}:#{v}"}}.join(",")
=> "d:11,d:22,f:33,f:44,f:55"
# case 2
hash.map {|k,vs| vs.each {|v| "#{k}:#{v}"}}.join(",")
=> "11,22,33,44,55"
唯一の違いは、ケース1がvs.map
を使用し、ケース2がvs.each
を使用することです。
ここで何が起こったのですか?
Array#each
は、配列の各要素に対して指定されたブロックを実行し、配列自体を返します。
Array#map
は、配列の各要素に対して指定されたブロックも実行しますが、その値がブロックの各反復の戻り値である新しい配列を返します。
例:このように定義された配列があると仮定します:
arr = ["tokyo", "london", "rio"]
それからeach
を実行してみてください:
arr.each { |element| element.capitalize }
# => ["tokyo", "london", "rio"]
戻り値は単純に同じ配列であることに注意してください。 each
ブロック内のコードは実行されますが、計算された値は返されません。また、コードには副作用がないため、この例は有用な作業を行いません。
対照的に、配列のmap
メソッドを呼び出すと、要素がmap
ブロックを実行する各ラウンドの戻り値である新しい配列が返されます。
arr.map { |element| element.capitalize }
# => ["Tokyo", "London", "Rio"]
副作用 は同じであり、リバースエンジニアリングに混乱をもたらします。
はい、両方とも配列を繰り返し処理します(実際には Enumerable )が混在するものを繰り返し処理しますが、 map は each であるブロックの結果で構成される配列は、元の配列を返すだけです。
each の戻り値は元の配列であり、Ruby code but map は 最も重要な機能ツール の1つです。
map
は、渡されたブロックまたは名前付きメソッドの結果を含む配列を返します。例えば:
2.2.3 :001 > [:how, :now, :brown, :cow].map &:to_s
=> ["how", "now", "brown", "cow"]
この場合、ブロックは渡さず、Symbol
だけを渡しましたが、class Symbol
オブジェクトにはto_proc
結果となるメソッド:
[:how.to_s, :now.to_s, ...]
ところで、mapはEnumerable while eachのメソッドであるため、ドキュメントを見つけるのに苦労しているかもしれません。 Enumerable module)はArrayのメソッドです。
雑学メモ:mapの実装はeachに基づいています。
マップがそれぞれの違いを示す簡単なデモを次に示します
a = ["a", "b", "c"];
#Array.map
p a.map {|item| "map_" + item}
#prints ["map_a", "map_b", "map_c"]
#Array.each
p a.each {|item| "map_" + item}
#prints ["a", "b", "c"]
Mapは["map_a", "map_b", "map_c"]
を返すのに対し、それぞれは単に反復するが元の配列["a", "b", "c"]
を返します。
したがって、それぞれが配列の処理に使用され、マップは処理された配列で何かをするために使用されます。
.each
は、最初に指定したのと同じ配列を返します。
[1,2,3].each { |i| i + 1 }
#=> [1,2,3]
.map
は、各ブロック呼び出しの結果から新しい配列を返します。
[1,2,3].map { |i| i + 1 }
#=> [2,3,4]
Array#eachメソッドは同じ配列を返します
a = [1,2,3,4,5]
a.object_id #70284994490700
b = a.each {|n| n + 2}
p b #[1,2,3,4,5]
b.object_id #70284994490700 <<--- it's the same as a
Array#mapメソッドは新しい配列を返します
c = [1,2,3,4,5]
c.object_id #70219117705860
d = c.map {|n| n + 2}
p d #[3,4,5,6,7]
d.object_id #70284994343620 <<---- it's different than c
mapをハッシュに使用すると、暗黙的にハッシュが配列にキャストされるため、
[["d", [11, 22]], ["f", [33, 44, 55]]]
vs.each {...}は、最後の評価のみを返します。これは、["d"、[11、22]]の場合は[11、22]、["f"、[ 33、44、55]]。最後の参加前に
[[11, 22], [33, 44, 55]]