JavaScript `减少` 到 Ruby `减少`

JavaScript `reduce` to Ruby `reduce`

在 JavaScript 中,一个 reduce 函数可能如下所示:

array.reduce((acc, cur, idx, arr) => {
    // body
}, starting_value);

我正在尝试以某种方式获得 arr 参数,它是原始数组的副本,我已经多次看到它很有用。这是我所能接受的:

array.each_with_index.reduce (starting_value) do |acc (cur, idx)|
    # body
end

我浏览 Ruby 文档已经有一段时间了(我实际上复制了 .each_with_index,因为我在某个地方找到了它),正在寻找任何像我一直在寻找的东西寻找。

老实说,从功能上讲,我可以将它分成多行并将某些内容存储在一个变量中,但是如果我可以将我的功能方法保留在 JavaScript 和 Ruby 中,我会非常高兴.

本质上:有什么方法可以在正文中获取arr参数吗?

reduce – 作为一个 Enumerable 方法 – 不知道它正在枚举的集合。

您必须自己合并数组,例如通过 then / yield_self:

[1, 2, 3].then do |arr|
  arr.each_with_index.reduce(4) do |acc, (cur, idx)|
    p acc: acc, cur: cur, idx: idx, arr: arr
    acc + cur
  end
end
# {:acc=>4, :cur=>1, :idx=>0, :arr=>[1, 2, 3]}
# {:acc=>5, :cur=>2, :idx=>1, :arr=>[1, 2, 3]}
# {:acc=>7, :cur=>3, :idx=>2, :arr=>[1, 2, 3]}
#=> 10

或链中某处:

[1, 2, 3].then do |arr|
  arr.map { |x| x * 2 }.then do |arr_2|
    arr_2.each_with_index.reduce(4) do |acc, (cur, idx)|
      p acc: acc, cur: cur, idx: idx, arr: arr, arr_2: arr_2
      acc + cur
    end
  end
end
# {:acc=>4, :cur=>2, :idx=>0, :arr=>[1, 2, 3], :arr_2=>[2, 4, 6]}
# {:acc=>6, :cur=>4, :idx=>1, :arr=>[1, 2, 3], :arr_2=>[2, 4, 6]}
# {:acc=>10, :cur=>6, :idx=>2, :arr=>[1, 2, 3], :arr_2=>[2, 4, 6]}
#=> 16

可以创建自定义 reduce 方法:

module Enumerable
  def reduce_with_self(initial_or_sym, sym = nil)
    if initial_or_sym.is_a?(Symbol)
      operator = initial_or_sym
      initial = nil
    else
      initial = initial_or_sym
      operator = sym
    end
    accumulator = initial
    each_with_index do |item, index|
      if index.zero? && initial.nil?
        accumulator = item
        next
      end
      accumulator = operator.nil? ? yield(accumulator, item, self) : accumulator.send(operator, item)
    end
    accumulator
  end
end

块的第三个参数将是对集合的引用:

> [1,2,3,4].reduce_with_self(0) do |acc, item, array|
>   p array
>   acc += item
> end
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
 => 10

> [1,2,3,4].reduce_with_self(2,:+)
 => 12 

> [1,2,3,4].reduce_with_self(:+)
 => 10 

当然,这个实现会比原来的慢:

require 'benchmark'

Benchmark.bm do |x|
  x.report('reduce') { 1000.times { (0..10000).reduce(0) { |acc, item| acc += item } } }
  x.report('reduce_with_self') { 1000.times { (0..10000).reduce_with_self(0) { |acc, item, array| acc += item } } }
end

       user     system      total        real
reduce  0.501833   0.000000   0.501833 (  0.502698)
reduce_with_self  0.955978   0.000000   0.955978 (  0.956809)