要求了解减少红宝石代码 [英] Requesting an insight on reduce ruby code

查看:94
本文介绍了要求了解减少红宝石代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始在可枚举部分解决hackerrank中的练习。
练习要求完成sum方法,该方法采用整数n,并将总和返回到系列的n个项。我从其他来源找到了解决方案,但我不太了解在这种情况下,reduce是如何工作的以及输出结果。

I started solving exercises in hackerrank in the enumerable section. The exercise asks to complete the sum method which takes an integer n and returns the sum to the n terms of the series. I found the solution from another source but I don't quite understand how the reduce works in this case and the output.

def sum_terms(n)
  series = []

  1.upto(n) do |i|
    series.push(i ** 2 + 1)
  end

  series.reduce(0, :+)
end

puts sum_terms(5)
# outputs 60


推荐答案

我们可以这样写这种方法:

We can write this method as follows:

def sum_terms(n)
  arr = create_series(n)
  arr.reduce(0, :+)
end

def create_series(n)
  series = []  
  1.upto(n) do |i|
    series.push(i**2 + 1)
  end
  series
end



sum_terms(5)
  #=> 60

步骤如下:

n = 5
arr = create_series(n)
  #=> [2, 5, 10, 17, 26] 
arr.reduce(0, :+)
  #=> 60

让我们首先看看方法 create_series 。此方法返回 n 个元素的数组,这些元素是整数 1 mapping >, 2 ,..., n 。 映射建议使用方法可枚举#map ,而不是创建一个空数组(系列),并向其中添加 n 个元素并返回该数组:

Let's first look at the method create_series. This method returns an array of n elements, those elements being a mapping of the integers 1, 2,...,n. "Mapping" suggests that it would be more sensible to use the method Enumerable#map than creating an empty array (series), appending n elements to it and returning that array:

def create_series(n)
  1.upto(n).map do |i|
    i**2 + 1
  end
end



create_series(5)
  #=> [2, 5, 10, 17, 26]

因为地图的块非常简短,我们可能会用花括号而不是 do..end

Because map's block is so brief we'd probably write it with braces rather than do..end:

def create_series(n)
  1.upto(n).map { |i| i**2 + 1 }
end

现在让我们来看一下 sum_terms 。对于 n = 5 ,它变为:

Now let's look at the method sum_terms. For n = 5, this becomes:

[2, 5, 10, 17, 26].reduce(0, :+) #=> 60

这是以下项的简写:

[2, 5, 10, 17, 26].reduce(0) { |tot,x| tot + x) #=> 60

这里我使用的是可枚举#reduce (又名 inject )它接受一个参数( 0 ),这是块变量 tot 的初始值。当数组的第一个元素为 reduce 的接收者( 2 )传递给地图的块,块变量 x 设置为等于该值。然后执行块计算:

Here I am using the form of Enumerable#reduce (aka inject) that takes an argument (0), which is the initial value of of the block variable tot. When the first element of the array that is reduce's receiver (2) is passed to map's block, the block variable x is set equal to that value. The block calculation is then performed:

tot + n
  #=> 0 + 2 => 2

tot (<$现在将c $ c> 0 )替换为该总和( 2 )。具体来说,将 memo 的值(此处为 tot )设置为等于该块中的最后执行的计算。接下来,将接收者的元素 5 传递到块,并设置 x 等于它。现在,块计算为:

The value of tot (0) is now replaced with that sum (2). Specifically, the value of the memo (here tot) is set equal to the last calculation performed in the block. Next, the element 5 of the receiver is passed to the block and x is set equal to it. The block calculation is now:

tot + n
  #=> 2 + 5 => 7

tot 设置为 7 。重复三次,导致 tot 依次等于 17 34 60 。由于此时没有更多元素要传递给接收器,因此块返回最终值 tot 60

and tot is set equal to 7. This is repeated thrice more, causing tot to successively equal 17, 34 and 60. As there are then no more elements to pass to the receiver the block returns the final value of tot, 60.

现在考虑以下问题:

[2, 5, 10, 17, 26].reduce(:+)                   #=> 60

简写为:

[2, 5, 10, 17, 26].reduce { |tot,x| tot + x }   #=> 60

这与第一次计算的区别在于减少没有参数。如文档中所述,在这种情况下, tot 最初设置为等于接收方的第一个值, 2 ,然后将接收器的其余四个元素分别传递给该块,从而导致 tot 依次等于 7 17 34 60

This differs from the first calculation in that reduce does not have an argument. As explained in the documentation, in this case tot is initially set equal to the first value of the receiver, 2, and then each of the four remaining elements of the receiver is passed to the block, causing tot to successively equal 7, 17, 34 and 60.

在这种情况下, reduce 的两种形式都给出相同的结果。

Clearly both forms of reduce give the same result in this case1.

我们可以改进此代码,但是可以跳过数组 [2、5、10、17、26] 的计算,如下所示:

We can improve on this code, however, by skipping the calculation of array [2, 5, 10, 17, 26] as follows:

1.upto(5).reduce(0) { |tot,i| tot + i**2 + 1 }  #=> 60

注意减少 必须这里的参数为零,因为

Notice that reduce must have an argument of zero here, as

1.upto(5).reduce { |tot,i| tot + i**2 + 1 }     #=> 59

等同于:

1 + 2.upto(5).reduce(0) { |tot,i| tot + i**2 + 1 }

这是不正确的。

执行此计算的更简单方法是使用方法 Enumerable#sum ,它在Ruby v2.4中首次亮相:

A simpler way of performing this calculation is to use the method Enumerable#sum, which made its debut in Ruby v2.4:

1.upto(5).sum { |i| i**2 + 1 }                  #=> 60

更简单的是计算 Faulhaber公式

n = 5
n + n*(n + 1)*(2*n + 1)/6                       #=> 60

1在某些情况下减少被分配了一个参数(通常为零)仅用于处理所谓的 edge case 。例如,假设我们希望对数组 arr 的元素求和并将其添加到 10 。我们可以编写 10 + arr.reduce(:+),只要 arr 不为空,它就可以正常工作。 10 + [] .reduce(:+)引发异常,但是,由于 []。reduce(:+)#=>零。相反, 10 + [] .reduce(0,:+)#=> 10

1 There are situations reduce is assigned an argument (often zero) merely to deal with a so-called edge case. Suppose, for example, we wished to sum the elements of an array arr and add that to 10. We could write 10 + arr.reduce(:+) which works fine as long as arr is not empty. 10 + [].reduce(:+) raises an exception, however, as [].reduce(:+) #=> nil. By contrast, 10 + [].reduce(0, :+) #=> 10.

这篇关于要求了解减少红宝石代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆