Array#inject の学習(1/n)
rubyのArray#injectを学習したくてネットサーフィンをしていたら見つけた。
はじめは写経していたのだけれど、問題に回答する感じで自分で途中からロジックを考えて、none?までやってみた。
せっかくなのでリポジトリを作ってみた。rails newしたのはrails cを起動したからったからだ。それ以外に実装の挙動を確認する方法が浮かばなかった。だけどやり方があるのだろうと思う。 こういうところがわからないんだよな、、、どうやったらいいんだろ。irbでファイルを読み込むとかかな。
injectの挙動がなんとなくわかった。inject それ自体の実装を見てみると理解しやすいかも。
例題
[2, 3, 4, 5].inject(0) {|result, item| result + item**2 } #=> 54
def inject(result, &blk) return result if empty? (drop 1).inject(yield(m, first), &blk) end
引数result は初期値の0が入る。&blkはブロック引数で {|result, item| result + item**2 } のことを意味している。 empty? はselfを対象にしている。最初は[2,3,4,5]が対象になるので、当然falseになる。 2行目でdprp 1をしている。こうすると[3,4,5]が作れる。dropは引数の数だけ配列の要素を頭から除き、残りを配列として戻すメソッドだ。 firstも対象がselfなので、この場合[2,3,4,5].first #=> 2だ。yieldはselfのブロックの処理をする。つまり( {|result, item| result + item**2 })を処理する。
つまり2行目は、こういう書き方が性格ではないかもだが、下記のようにループする。はず。
[3,4,5].inject({|0, 2| 0 + 3**2 }=>4, {|result, item| result + item**2 }) [4,5].inject({|4,3 | 4 + 3**2 }=>13, {|result, item| result + item**2 }) [5].inject({|13,4 | 13 + 4**2 }=>29, {|result, item| result + item**2 }) [].inject({|29,5 | 13 + 5**2 }=>54, {|result, item| result + item**2 })
最後のinjectメソッドは[]空配列に対して呼ばれるので、return m となり、mに入ってる54 が返り値となる。
ブロックの結果をさらに自分の引数として利用できる。これが再帰的というやつなのか。 とにかく、このように要素ごとにブロックの処理をして、その結果を利用してまたブロックを評価していく。最後の要素が終わったときの最後の評価を返り値とする。それがinjectメソッド、という現状の理解。 かなりふわっとしているが、とりあえずいまの自分はこのように理解している、というメモ。
(了)