いわゆるscanl関数をRubyで書いてみる
scanl関数は、(a -> b -> a)型の関数と、初期値aとリスト[b]が与えられて、順番に引数に渡された関数を適用した計算をして計算結果のリストを返す関数。foldlの計算の中間結果を集めたリストを返すとイメージしてもらえば。
scanl :: (a -> b -> a) -> a -> [b] -> [a]
Prelude:scanl :: (a -> b -> a) -> a -> [b] -> [a]
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:scanl
Prelude> scanl (+) 100 [1..10] [100,101,103,106,110,115,121,128,136,145,155]
Scalaにもちゃんとあるよ。
scala> (1 to 10).scanLeft(100){(a,b) => a + b } res0: scala.collection.immutable.IndexedSeq[Int] = Vector(100, 101, 103, 106, 110, 115, 121, 128, 136, 145, 155)
scala.collection.TraversableLike#scanLeft
Rubyでは......?
無いので作りました。
module Enumerable def scanl(z,&block) rv = [z] inject(z){|a,b| r = yield(a,b) rv << r r } rv end end
動かしてみる。
ozaki@mbp $ irb irb(main):001:0> module Enumerable irb(main):002:1> def scanl(z,&block) irb(main):003:2> rv = [z] irb(main):004:2> inject(z){|a,b| irb(main):005:3* r = yield(a,b) irb(main):006:3> rv << r irb(main):007:3> r irb(main):008:3> } irb(main):009:2> rv irb(main):010:2> end irb(main):011:1> end => nil irb(main):012:0> (1..10).to_a.scanl(100){|a,b| a+b} => [100, 101, 103, 106, 110, 115, 121, 128, 136, 145, 155]
ところで、俺はrubyのEnumerable#injectって名前が大嫌いなので、
module Enumerable alias :foldl :inject # inject must die undef_method :inject end
これで心の安寧が得られる。
irb(main):024:0> module Enumerable irb(main):025:1> alias :foldl :inject # inject must die irb(main):026:1> undef_method :inject irb(main):027:1> end => Enumerable irb(main):028:0> (1..10).inject(100){|a,b| a+b} NoMethodError: undefined method `inject' for 1..10:Range from (irb):28 from (irb):28 irb(main):029:0> (1..10).foldl(100){|a,b| a+b} => 155