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.

+2


a source to share


6 answers


Your own attempt at help collect

was already very close; just keep adding up the previous values ​​as you go.



my_array = [1, 5, 8, 11, -6]
previous_values = 0
my_array.collect { |value| previous_values += value }
# => [1, 6, 14, 25, 19]

      

+6


a source


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.

+9


a source


x = 0
[1, 5, 8, 11, -6].map {|a| x = x +a }

      

+3


a source


my_array.each_index{|i| my_array[i] += my_array[i-1] if i>0 }

      

or

my_array.inject([]){|memo, item| memo << item + memo.last.to_i }

      

+1


a source


You can use this:

my_array = [1, 5, 8, 11, -6]
final_array = []

my_array.inject(0) {|res, it| final_array << res + it; res + it}

      

+1


a source


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]

      

+1


a source







All Articles