読者です 読者をやめる 読者になる 読者になる

( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

いわゆるscanl関数をRubyで書いてみる

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