ruby 数字的求和数组[重复]

des4xlb0  于 2022-12-03  发布在  Ruby
关注(0)|答案(2)|浏览(162)

此问题在此处已有答案

How to sum array of numbers in Ruby?(16个答案)
八年前就关门了。
问:写一个方法,sum,它接受一个数字数组并返回这些数字的和。
答:

def sum(nums)
  total = 0

  i = 0
  while i < nums.count
    total += nums[i]

    i += 1
  end

  # return total
  total
end

一定有别的方法不用while来解决这个问题,对吧?有人知道怎么做吗?
编辑:这不是考试或测试。这是github上为app academy提供的一个练习题。他们提供了问题和答案作为例子。我只是读到优秀的程序员不喜欢使用while或unless,所以我很好奇我是否可以学习一些更好的方法来解决这个问题。比如使用enumerable?(显然,Ruby的Noob在这里...)
此外,我会喜欢任何演练或方法,我应该学习..这个问题也是不同的,因为我要求使用这些数据的具体例子。

mqkwyuun

mqkwyuun1#

通常的做法是:

def sum(nums) nums.reduce(&:+) end

它是这样的缩写:

def sum(nums)  nums.reduce(0) { |total, num| total + num } end

我看到Neil发布了一个类似的解决方案,我在这里只需要注意reduceinject是同一个方法的两个名称- Ruby有几个类似的别名,这样习惯于其他不同语言的人就可以找到他们想要的东西。当使用reduce/inject的具名方法时,这是选择性的,但在其他情况下则不是。
解释如下。
在Ruby中,通常不使用显式循环(forwhile,等等).相反,您可以调用正在迭代的集合上的方法,并向它们传递一个 block 代码,以在每个项上执行. Ruby的语法将block放在方法的参数之后,在do... end{... }之间,因此它看起来像传统的命令式流控制,但工作方式不同。
基本迭代方法为each

[1,2,3].each do |i| puts i end

这将调用块do |i| puts i end三次,传递1,然后传递2,最后传递3。|i|是一个块参数,它告诉Ruby每次将传递到块中的值放在哪里。
但是each只是丢弃了块调用的返回值(在本例中,是puts返回的三个nil)。如果你想对这些返回值做些什么,你必须调用一个不同的方法。例如,map返回一个返回值数组:

[1,2,3].map do |i| puts i end
#=> [nil, nil, nil]

这在这里不是很有趣,但是如果块返回一些东西,它会变得更有用:

[1,2,3].map do |i| 2*i end  
#=> [2,4,6]

如果你想把结果 * 合并 * 成一个聚合返回值,而不是返回一个与输入大小相同的数组,这时你需要reduce。除了一个块,它还需要一个额外的参数,块本身也用一个额外的参数调用。与这个参数对应的额外参数称为“accumulator”;第一次调用该块时,它获取最初传递给reduce的参数,但从那时起,它获取对该块的 previous 调用的返回值,这是每个块调用将信息沿着给下一个块的方式。
这使得reducemap更通用;实际上,你可以通过传入一个空数组并将块添加到其中来从reduce构建map

[1,2,3].reduce([]) do |a,i| a + [2*i] end 
#=> [2,4,6]

但是由于map已经定义好了,所以通常只会用它来做这个,而且只会用reduce来做一些更简化的事情:

[1,2,3].reduce(0) do |s, i| s + 2*i end  
#=> 12

......这也是我们解决你问题的方法。
Neil和我采取了一些额外的捷径。首先,如果一个块只对它的参数调用一个方法并返回结果,那么你可以通过在方法名前加上前缀&:来得到一个等价的块。也就是说:

some_array.reduce(x) do |a,b| a.some_method(b) end

可以更简单地改写为:

some_array.reduce(x, &:some_method)

由于Ruby中的a + b实际上只是编写方法调用a.+(b)的一种更熟悉的方式,这意味着您只需传入&:+就可以将数字相加:

[1,2,3].reduce(0, &:+)
#=> 6

接下来,reduce的初始累加器值是可选的;如果省略它,那么第一次调用该块时,它将获得数组的前 * 两 * 个元素。

[1,2,3].reduce(&:+)
#=> 6

最后,当你传入一个不是文本代码块的块时,你通常需要&。你可以把块转换成Proc对象,并把它们存储在变量中,通常把它们当作任何其他值,包括把它们作为常规参数传递给方法调用。所以当你想在方法调用中使用一个块作为 block 时,您可以使用&来指示。
一些方法,包括reduce,也会接受一个空符号(比如:+)并为你创建Proc/block; Neil利用了这一点。但是其他迭代器方法,比如map,就不是这样工作的:

irb(main):001:0> [-1,2,-3].map(:abs)
ArgumentError: wrong number of arguments (1 for 0)
from (irb):1:in `map'
from (irb):1
from /usr/bin/irb:12:in `<main>'

所以我总是使用&

irb(main):002:0> [-1,2,-3].map(&:abs)
#=> [1, 2, 3]

Ruby有很多很好的在线教程,关于map/reduce和相关概念的更多一般信息,以及如何将它们应用到解决问题中,你应该搜索“函数式编程”的介绍,之所以叫它,是因为它对待“函数”(也就是可执行代码块,在Ruby中实现为Proc对象)作为值,就像数字和字符串一样,可以传递,分配给变量等。

b09cbbtk

b09cbbtk2#

在Ruby中,最常用的方法可能是:

nums.inject(:+)

......虽然这基本上隐藏了所有的工作,所以这取决于测试试图测试什么。
Array#inject的文档

相关问题