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

时间:2010-05-17 07:59:38

标签: ruby arrays iteration arraycollection

假设我有以下数组:

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

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

final_array = [1, 6, 14, 25, 19]

我尝试过这样的事情:

my_array.collect {|value| value + previous_values }

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

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

任何帮助将不胜感激。

6 个答案:

答案 0 :(得分:9)

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

[1, 5, 8, 11, -6].scan(:+)

显然,我最近一直在阅读太多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

如果你希望Enumerable#scan表现得像Enumerable#reduce,即采用可选的初始参数和可选符号,我们需要稍微增强我们的版本,并使用从Rubinius {{1}中窃取的一些参数按摩代码}:

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

如果您再次遇到此类问题,请使用其他语言,请记住术语 scan prefix-sum ,这些功能通常非常常见。我不太明白为什么Ruby没有它们。

答案 1 :(得分:6)

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

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

答案 2 :(得分:3)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

您可以使用:

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

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

答案 5 :(得分:1)

我为此预制了一个预分配结果数组的宝石。即使对于具有大量元素的Enumerables,操作也非常快。与使用Enumerable #map的解决方案不同,语法与Enumerable#reduce的语法完全相同,并且可以选择在引擎盖下使用Enumerable#reduce,以防你使用猴子修补#reduce。这个名字取自Clojure的同名职能。

https://rubygems.org/gems/reductions

安装:

$ gem install reductions

使用:

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]