Rubyのmap、reduce処理について
Rubyのmap処理が結構ややこしいのでまとめてみた。
最後にreduceメソッドについても触れる。
1.RubyのArray#map, Hash#mapメソッドについて
RubyのArrayクラス、Hashクラスのmapメソッドは、ブロックを引数にとり、要素の数だけループをまわし、その戻り値をarrayに格納する。mapメソッドは、別名collectメソッドともいう。
mapメソッドが使われる例として、以下のようなものがあげられる。
#1.arrayの要素に処理をしてarrayに格納する array = [ 1, 2, 3, 4, 5, 6 ] array.map{ |num| num.to_s } #=> [ "1", "2", "3", "4", "5", "6" ] #2.hashのvalueをarrayに格納する hash = { key1: 1, key2: 2, key3: } hash.map{ |k,v| v } #=>[ 1, 2, 3 ] #2については、以下の方法もある hash.values #=> [ 1, 2, 3 ]
2.Rubyのmap処理を短く記述する
RubyではActiveSupportというgemをrequireすることで、上記のmap処理をより簡単に記述することができる。
その記法について、説明する。
#1.arrayの要素に処理をしてarrayに格納する array = [ 1, 2, 3, 4, 5, 6 ] array.map(&:to_s) #=> [ "1", "2", "3", "4", "5", "6" ]
mapメソッドの引数の先頭についている「&」は、その引数がblockであることを表す。
Rubyでは、ほとんどのものがobjectだが、blockはobjectではない。そこで、「&」のあとにはblock内の手続きとコンテキストをオブジェクト化した、Procオブジェクトが期待される。
しかし、上記の例では「&」のあとにProcオブジェクトがきている訳ではない。なぜ、このような記法が許されるかというと、requireしたRubyのgemであるActiveSupportが「&」のあとにあるオブジェクトにto_procメソッドがある場合、to_procメソッドを呼び出してからブロックにすると定義しているからである。上記の例では、シンボルオブジェクトにto_proc メソッドが定義されていたから、そのメソッドが呼び出され、Procオブジェクトに変換されたものが、「&」によりブロックに変換され、map処理が正常に行われた。
3.Enumerable#reduceメソッドについて
Enumerable#reduceメソッドは、ArrayやHashの各値をブロックを使って繰り返し計算するのに使う。ブロックに順に、「Arrayやhashの要素1、Arrayやhashの要素2」、「一つ前のブロック処理の戻り値、Arrayやhashの要素3」、「一つ前のブロック処理の戻り値、Arrayやhashの要素4」、...を渡す。メソッドの戻り値は、ブロックが最後に返した値になる。reduceメソッドは、別名、injectメソッドともいう。
以下、reduceメソッドの使用例を紹介する。
numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] numbers.reduce{ | sum, n | sum + n } #=> 55 #reduceの引数を指定すると、ブロックに順に、「引数、ArrayやHashの要素1」、「一つ前のブロックの戻り値、ArrayやHashの要素2」、「一つ前のブロックの戻り値、ArrayやHashの要素3」、...を渡す numbers.reduce(100){ | diff, n | diff - n } #=> 45
以上