2

可以说我有以下数组:

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

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

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

我试过做这样的事情:

my_array.collect {|value| value + previous_values }

但显然这不起作用,因为我不知道如何获取数组中的先前值。

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

任何帮助,将不胜感激。

4

6 回答 6

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 窃取的一些参数按摩代码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

有了这个增强版本,上面的例子现在可以工作了:

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

如果您再次遇到此类问题,请记住另一种语言的术语scanprefix-sum,此类功能通常很常见。我不太明白为什么 Ruby 还没有它们。

于 2010-05-17T09:51:40.397 回答
6

您自己的尝试collect已经非常接近了;只需不断总结以前的值即可。

my_array = [1, 5, 8, 11, -6]
previous_values = 0
my_array.collect { |value| previous_values += value }
# => [1, 6, 14, 25, 19]
于 2010-05-17T08:48:16.820 回答
3
x = 0
[1, 5, 8, 11, -6].map {|a| x = x +a }
于 2010-05-17T08:18:44.493 回答
1

我为此制作了一个 gem,它预先分配了结果数组。该操作非常快,即使对于具有大量元素的 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]
于 2015-03-19T22:11:11.223 回答
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 }
于 2010-05-17T08:16:34.977 回答
1

你可以使用这个:

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

my_array.inject(0) {|res, it| final_array << res + it; res + it}
于 2010-05-17T08:26:37.110 回答