injectが分からん。。→inject便利!
Enumerable.injectの意味がよく分からないので調べてみる。
まずリファレンス。
http://www.ruby-lang.org/ja/man/html/Enumerable.html#inject
inject([init]) {|result, item| ... } (ruby 1.7 feature)
最初に初期値 init と self の最初の要素を引数にブロックを実行します。2 回目以降のループでは、前のブロックの実行結果と self の次の要素を引数に順次ブロックを実行します。そうして最後の要素まで繰り返し、最後のブロックの実行結果を返します。
なんのことやら。。
以下のコードで実験。
irb(main):017:0> [1,2,3].inject(0) {|r,i| puts "r:#{r}, i:#{i}"} r:0, i:1 r:, i:2 r:, i:3 => nil
最初のputsでnilを返しているから、次回以降のresultにnilが入るのだね。なるほど。
ではitemを返すようにすると?
→ 最後の要素を返すことになる。
irb(main):022:0> [1,2,3].inject(0) {|r,i| puts "r:#{r}, i:#{i}"; i} r:0, i:1 r:1, i:2 r:2, i:3 => 3
ではよくあるsumを書いてみよう。
irb(main):023:0> [1,2,3].inject(0) {|r,i| puts "r:#{r}, i:#{i}"; r+i} r:0, i:1 r:1, i:2 r:3, i:3 => 6
初期値なしの場合は最初の2要素がresultとitemに入るらしい。
irb(main):024:0> [0,1,2,3].inject {|r,i| puts "r:#{r}, i:#{i}"; r+i} r:0, i:1 r:1, i:2 r:3, i:3 => 6
しかしこれで何が嬉しいの?というのがよく分からん・・。と思っていたら、
id:ninjatottori:20080411#1207903182
を発見。
シンプルに書けるところがポイントかー。なるほど。
フィボナッチ数列を作ってみる。
each使用版。
r = [0,1] (0..10).each{ r << r[-2] + r[-1] } r => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
inject使用版。確かに簡潔だな〜。
(0..10).inject([0,1]){|r,i| r << r[-2] + r[-1]} => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
joinも書けてしまう。
%w{ a b c }.inject{|r,i| r + "," + i} => "a,b,c" [0,1,2,3].inject{|r,i| r.to_s + "," + i.to_s} => "0,1,2,3"
なんとなく分かった。
r = ○○
array.each{|i| r = (iが絡む式)}
r
の略記法なんだな。
あれ?ということはArrayの重複チェック(id:craftone:20080502#1209737230)もこっちの方が良いな〜。
injectすげー!
class Array def overlapped an_hash = Hash.new self.inject([]){|r,i| an_hash.include?(i) ? (r << i) : (an_hash[i] = nil; r) } end end