SmalltalkとLispから来たメソッドmap と collect、reduce と inject
SmalltalkとLispから来たメソッドmap と collect、reduce と injectをメモ。
【参考】
map と collect、reduce と inject ―― 名前の違いに見る発想の違い
【Ruby】
[3, 4, 5, 6].map {|i| i + 1 }
=> [4, 5, 6, 7]
【Lisp】
(map 'list (lambda (i) (+ i 1)) '(3 4 5 6))
【Ruby】
[3, 4, 5, 6].collect {|i| i + 1 }
=> [4, 5, 6, 7]
【Smalltalk】
#(3 4 5 6) collect: [:i | i + 1 ]
【Ruby】
[3, 4, 5, 6].reduce {|i, j| i + j }
[3, 4, 5, 6].reduce(:+)
=> 18
【Lisp】
(reduce (lambda (i j) (+ i j)) '(3 4 5 6))
(reduce '+ '(3 4 5 6))
【Ruby】
[3, 4, 5, 6].inject {|i, j| i + j }
[3, 4, 5, 6].inject(0) {|i, j| i + j }
[3, 4, 5, 6].inject(:+)
=> 18
【Smalltalk】
#(3 4 5 6) inject: 0 into: [:i :j | i + j ]
(引用開始)
map と collect の発想の違い
まずは map と collect の発想の違いを見てみましょう。
map
map は「データ構造を保ったまま3、あるルールに従って元のデータ構造を別データ構造に変換する」という発想になります。
(中略)
collect
collect は「データ構造内の全ての要素に対して、ある処理を繰り返し実行し、その結果を集めたもの」という発想になります。
(中略)
reduce と inject の発想の違い
次は、reduce と inject の発想の違いを見てみましょう。
reduce
reduce は「あるルールに従ってデータ構造内の要素数を縮小していき、最後に残った値を返す」という発想になります。
(中略)
inject
inject は「値をプールしておくバケツを用意しておき、データ構造内の全ての要素をひとつずつ、ある処理にしたがってバケツに注入していく」という発想になります。
(中略)
しかし別々の発想をしていても、それぞれで「こうした処理は必要だ」という結論になって、違う名前で同じ機能が実装されたということはとても面白いですね。実は今回取り上げた二つの機能、ひとつは「map と collect」が表現している「巨大なデータを構造を保ったまま別のデータに変換する」機能4、もうひとつは「reduce と inject」が表現している「巨大なデータのすべての要素を使って何らかの計算結果を求める」機能5は、巨大なデータを処理する場合の最も基本的な処理、つまり基礎となる機能なのです。
(中略)
5.数学ではこれを「畳み込み」と呼びます。
(引用終了)
mapはRuby初心者も慣れるが、injectの発想は面白い。
injectでは明示的にブロックを渡すのではなく、[3, 4, 5, 6].inject(:+) のように、メソッドのシンボルを渡すことで配列の要素に作用させる。
この辺りの考え方に、Rubyが過去の言語の良い所取りをしている感じがする。
| 固定リンク
「Ruby」カテゴリの記事
- 「コーディングを支える技術」は良い本だ(2022.05.26)
- 知識は経験よりも大切か、経験は知識よりも勝るのか、SECIモデルは相互作用を語る(2022.04.26)
- 「RubyやRailsは終わった」という記事のリンク(2022.01.09)
- ITの技術や知識はツールの習得と表裏一体である(2021.03.26)
- JRubyの終焉(2020.06.09)
コメント