Ruby中的累积数组和

什么是最简单,最类似于Ruby的计​​算数组累积和的方法?

例:

[1,2,3,4].cumulative_sum 

应该回来

 [1,3,6,10] 

 class Array def cumulative_sum sum = 0 self.map{|x| sum += x} end end 

这是一种方式

 a = [1, 2, 3, 4] a.inject([]) { |x, y| x + [(x.last || 0) + y] } 

如果答案是多个语句,那么这将更清晰:

 outp = a.inject([0]) { |x, y| x + [x.last + y] } outp.shift # To remove the first 0 
  irb> a = (1..10).to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] irb> a.inject([0]) { |(p,*ps),v| [v+p,p,*ps] }.reverse[1..-1] #=> [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] 

我们也可以从Haskell那里得到一个注释,制作一个ruby版本的scanr 。

 irb> class Array > def scanr(init) > self.inject([init]) { |ps,v| ps.unshift(yield(ps.first,v)) }.reverse > end > end #=> nil irb> a.scanr(0) { |p,v| p + v } => [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55] irb> a.scanr(0) { |p,v| p + v }[1..-1] => [1, 3, 6, 10, 15, 21, 28, 36, 45, 55] irb> a.scanr(1) { |p,v| p * v } => [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] 

你也可以阅读scanl – 你需要的function,但据我所知,这还没有在Ruby中实现。 以下是它的示例和示例源代码: http : //billsix.blogspot.com/2008/11/functional-collection-patterns-in-ruby.html

UPD:上面的链接已经死了,所以我会说我的Ruby实现Wolfram Mathematica的FoldList []作为gem“mll”的一部分可以简化为OP的目的,同时是Enumerable:

 def fold_list array start = 0 Enumerator.new do |e| array.each do |i| e << start += i end end end irb> fold_list([1,2,3]).to_a => [1, 3, 6] 

还有一种方法(虽然我更喜欢khell的)

 (1..10).inject([]) { |cs, i| cs << i + (cs.last || 0) } 

我在发布答案后看到了hrnt发布的答案。 虽然两种方法看起来相同,但由于在每个注入周期中使用相同的arrays,因此上述解决方案更有效。

 a,r = [1, 2, 3, 4],[] k = a.inject(r) { |x, y| x + [(x.last || 0) + y] } p r.object_id # 35742260 p k.object_id # 35730450 

你会注意到r和k是不同的。 如果您对上述解决方案执行相同的测试:

 a,r = [1, 2, 3, 4],[] k = a.inject(r) { |cs, i| cs << i + (cs.last || 0) } p r.object_id # 35717730 p k.object_id # 35717730 

r和k的对象id是相同的。

为另一种方法发掘这种方法,即就地修改数组

 class Array def cumulative_sum! (1..size-1).each {|i| self[i] += self[i-1] } self end end 

也可以推广:

  def cumulate!( &block ) (1..size-1).each {|i| self[i] = yield self[i-1], self[i] } self end >> (1..10).to_a.cumulate! {|previous, next| previous * next } => [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] 

试试这个代码

 [1,2,3,4].inject([]){ |acc, value| acc << acc.last.to_i + value.to_i } => [1, 3, 6, 10] 

我们想要的Haskell函数是scanr ,而不是scanr

 class Array def scanl(init) self.reduce([init]) { |a, e| a.push(yield(a.last, e)) } end end [1,2,3,4].scanl(0) { |a, b| a + b }[1..-1] => [1, 3, 6, 10]