假设我有以下数组:
my_array = [1, 5, 8, 11, -6]
我需要遍历此数组并将当前值之前的值相加。一个例子可能更容易理解。我需要返回一个看起来像这样的数组:
final_array = [1, 6, 14, 25, 19]
我尝试过这样的事情:
my_array.collect {|value| value + previous_values }
但显然这不起作用,因为我无法弄清楚如何获取数组中的先前值。
我是一个编程菜鸟,所以这可能比我做的更容易。我很确定我需要使用收集或注入,但我似乎无法弄清楚如何做到这一点。
任何帮助将不胜感激。
答案 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]