如何为数组中的所有先前值添加值

Jam*_*mes 2 ruby arrays iteration arraycollection

可以说我有以下数组:

my_array = [1, 5, 8, 11, -6]
Run Code Online (Sandbox Code Playgroud)

我需要迭代这个数组并将当前值之前的值相加.一个例子可能更容易理解.我需要返回一个看起来像这样的数组:

final_array = [1, 6, 14, 25, 19]
Run Code Online (Sandbox Code Playgroud)

我尝试过这样的事情:

my_array.collect {|value| value + previous_values }
Run Code Online (Sandbox Code Playgroud)

但显然这不起作用,因为我无法弄清楚如何获取数组中的先前值.

我是一个编程菜鸟,所以这可能比我做的更容易.我很确定我需要使用收集或注入,但我似乎无法弄清楚如何做到这一点.

任何帮助,将不胜感激.

Jör*_*tag 9

我的第一直觉是:"这显然是一个扫描(又名前缀 - 总和),因此应该很容易":

[1, 5, 8, 11, -6].scan(:+)
Run Code Online (Sandbox Code Playgroud)

显然,我最近一直在阅读太多Haskell和Scala,因为Ruby中没有Enumerable#scan ...但是:

module Enumerable
  def scan(initial=first, &block)
    [initial].tap {|res| 
      reduce {|acc, el| 
        block.(acc, el).tap {|el|
          res << el
        }
      }
    }
  end
end
Run Code Online (Sandbox Code Playgroud)

如果你想Enumerable#scan表现得像Enumerable#reduce,即采取一个可选的初始参数和一个可选的符号,我们需要稍微增强我们的版本,一些参数按摩从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
Run Code Online (Sandbox Code Playgroud)

使用此增强版本,上面的示例现在可以正常工作:

p [1, 5, 8, 11, -6].scan(:+)
# => [1, 6, 14, 25, 19]
Run Code Online (Sandbox Code Playgroud)

如果你再次遇到这种问题,用另一种语言,请记住术语scanprefix-sum,这些函数通常很常见.我不太明白Ruby为什么没有它们.


Ark*_*kku 6

你自己的尝试collect已经非常接近; 只需在你去的时候总结以前的值.

my_array = [1, 5, 8, 11, -6]
previous_values = 0
my_array.collect { |value| previous_values += value }
# => [1, 6, 14, 25, 19]
Run Code Online (Sandbox Code Playgroud)