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)
但显然这不起作用,因为我无法弄清楚如何获取数组中的先前值.
我是一个编程菜鸟,所以这可能比我做的更容易.我很确定我需要使用收集或注入,但我似乎无法弄清楚如何做到这一点.
任何帮助,将不胜感激.
我的第一直觉是:"这显然是一个扫描(又名前缀 - 总和),因此应该很容易":
[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)
如果你再次遇到这种问题,用另一种语言,请记住术语scan和prefix-sum,这些函数通常很常见.我不太明白Ruby为什么没有它们.
你自己的尝试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)