How to add a value to all previous values ββin an array
Let's say I have the following array:
my_array = [1, 5, 8, 11, -6]
I need to loop over this array and add the values ββup to the current value together. An example will probably be easier to understand. I need to return an array that should look something like this:
final_array = [1, 6, 14, 25, 19]
I tried to do something like this:
my_array.collect {|value| value + previous_values }
But obviously it doesn't work because I can't figure out how to get the previous values ββin the array.
I am programming a noob so it may be easier than I am doing it. I'm sure I need to use either collect or inject, but I can't figure out how to do that.
Any help would be greatly appreciated.
a source to share
My very first instinct: "This is obviously a scan (aka prefix-sum), so it should be easy":
[1, 5, 8, 11, -6].scan(:+)
Obviously I've been reading too much Haskell and Scala lately, because Ruby does not & hellip Enumerable#scan
; yet:
module Enumerable
def scan(initial=first, &block)
[initial].tap {|res|
reduce {|acc, el|
block.(acc, el).tap {|el|
res << el
}
}
}
end
end
If you want to Enumerable#scan
behave like Enumerable#reduce
, i.e. accepts an optional start argument and an optional character, we need to improve our version a bit with some argument of the massaging code stolen from Rubinius Enumerable#reduce
:
module Enumerable
def scan(initial=nil, sym=nil, &block)
args = if initial then [initial] else [] end
unless block_given?
args, sym, initial = [], initial, first unless sym
block = ->(acc, el) { acc.send(sym, el) }
end
[initial || first].tap {|res|
reduce(*args) {|acc, el|
block.(acc, el).tap {|e|
res << e
}
}
}
end
end
In this extended version, the above example works:
p [1, 5, 8, 11, -6].scan(:+)
# => [1, 6, 14, 25, 19]
If you have this problem again, in another language, remember the terms scan and prefix-sum, such functions are usually quite common. I don't quite understand why Ruby is no longer there.
a source to share
I made a gem for this that preallocates an array of results. The operation is very fast, even for Enumerables with many elements. Unlike solutions using Enumerable # map, the syntax is exactly like the syntax of Enumerable # reduce and can optionally use Enumerable # reduce under the hood if you have a fixed # monkey. The name was taken from the Clojure function of the same name.
https://rubygems.org/gems/reductions
For installation:
$ gem install reductions
For use:
require 'reductions'
[1, 5, 8, 11, -6].reductions(:+) #=> [1, 6, 14, 25, 19]
[1, 5, 8, 11, -6].reductions{|a| a + b} #=> [1, 6, 14, 25, 19]
# With an inital value:
[1, 5, 8, 11, -6].reductions(1,:+) #=> [1, 2, 7, 15, 26, 20]
[1, 5, 8, 11, -6].reductions(1){|a| a + b} #=> [1, 2, 7, 15, 26, 20]
a source to share