什么是最简单,最像Ruby的计算数组累积和的方法?
示例:
[1,2,3,4].cumulative_sum
应该返回
[1,3,6,10]
答案 0 :(得分:36)
class Array
def cumulative_sum
sum = 0
self.map{|x| sum += x}
end
end
答案 1 :(得分:10)
这是一种方式
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
答案 2 :(得分:7)
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那里得到一个注释,并制作一个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]
答案 3 :(得分:2)
另外你可以阅读有关scanl
- 你需要的功能,但据我所知,这还没有在Ruby中实现。以下是它的示例和示例源代码:http://billsix.blogspot.com/2008/11/functional-collection-patterns-in-ruby.html
<强> UPD:强> 上面的链接已经死了,所以我会说我的Ruby实现Wolfram Mathematica的FoldList[]作为gem“mll”here的一部分可以简化为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]
答案 4 :(得分:1)
另一种方法(虽然我更喜欢 khell )
(1..10).inject([]) { |cs, i| cs << i + (cs.last || 0) }
我在发布答案后看到了 hrnt 发布的答案。虽然两种方法看起来相同,但由于在每个注入周期中使用相同的数组,因此上述解决方案更有效。
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是相同的。
答案 5 :(得分:1)
为另一种方法发掘这个,就地修改数组
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]
答案 6 :(得分:1)
试试此代码
[1,2,3,4].inject([]){ |acc, value| acc << acc.last.to_i + value.to_i }
=> [1, 3, 6, 10]
答案 7 :(得分:0)
我们想要的Haskell函数是scanl
,而不是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]