What is the slickest, most Ruby-like way of calculating the cumulative sum of an array?
Example:
[1,2,3,4].cumulative_sum
should return
[1,3,6,10]
What is the slickest, most Ruby-like way of calculating the cumulative sum of an array?
Example:
[1,2,3,4].cumulative_sum
should return
[1,3,6,10]
The interesting bit is along the lines of
x=0
cumulative_sum = input_array.map do |e|
x = x+e
x
end
Here is one way
a = [1, 2, 3, 4]
a.inject([]) { |x, y| x + [(x.last || 0) + y] }
If it is OK that the answer is more than one statement, then this would be cleaner:
outp = a.inject([0]) { |x, y| x + [x.last + y] }
outp.shift # To remove the first 0
class Array
def cumulative_sum
sum = 0
self.map{|x| sum += x}
end
end
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]
We could also take a note from Haskell and make a ruby version of 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]
One more approach ( though I prefer khell's)
(1..10).inject([]) { |cs, i| cs << i + (cs.last || 0) }
I saw the answer posted by hrnt after posting my answer. Though two approaches look the same, solution above is more efficient as the same array is used in each inject cycle.
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
You will notice r and k are different. If you do the same test for the solution above:
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
The object id for r and k are the same.
Also you can read about scanl
— feature you need, but that isn't yet implement in Ruby, as far as i know.
Here are examples and sample source code of it.
http://billsix.blogspot.com/2008/11/functional-collection-patterns-in-ruby.html