tawara's blog

雑記。個人の見解です。

Array#inject の学習(1/n)

melborne.github.io

rubyのArray#injectを学習したくてネットサーフィンをしていたら見つけた。

はじめは写経していたのだけれど、問題に回答する感じで自分で途中からロジックを考えて、none?までやってみた。

せっかくなのでリポジトリを作ってみた。rails newしたのはrails cを起動したからったからだ。それ以外に実装の挙動を確認する方法が浮かばなかった。だけどやり方があるのだろうと思う。 こういうところがわからないんだよな、、、どうやったらいいんだろ。irbでファイルを読み込むとかかな。

github.com

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メソッド、という現状の理解。 かなりふわっとしているが、とりあえずいまの自分はこのように理解している、というメモ。

(了)