如何在Ruby中求和数字数组?

How to sum array of numbers in Ruby?

我有一个整数数组。

例如:

1
array = [123,321,12389]

有没有什么好方法可以得到它们的总数?

我知道,那个

1
2
sum = 0
array.each { |a| sum+=a }

会起作用。


或者尝试Ruby1.9方法:

1
array.inject(0, :+)

注:需要0基本情况,否则将在空数组上返回nil

1
2
3
4
> [].inject(:+)
nil
> [].inject(0, :+)
0


试试这个:

1
array.inject(0){|sum,x| sum + x }

参见Ruby的可枚举文档

(注:需要0基本情况,以便在空数组上返回0,而不是在nil上返回)


1
array.reduce(0, :+)

虽然与array.inject(0, :+)相当,但随着mapreduce编程模型的兴起,术语reduce进入了一个更常见的方言。

注入、减少、折叠、积累和压缩都是一类折叠功能的同义词。我发现跨代码库的一致性最重要,但是由于不同的社区倾向于使用一个词而不是另一个词,因此了解替代词仍然很有用。

为了强调map-reduce的措辞,这里有一个版本,它对数组中的结果稍微宽容一点。

1
array.map(&:to_i).reduce(0, :+)

其他相关阅读:

  • http://ruby doc.org/core-1.9.3/enumerable.html method-i-inject
  • http://en.wikipedia.org/wiki/mapreduce网站
  • http://en.wikipedia.org/wiki/fold_u(高阶_函数)


或者(只是为了比较),如果您安装了Rails(实际上只是ActiveSupport):

1
2
require 'activesupport'
array.sum


对mokeypatch基类来说是危险的,现在Ruby2.4.0对可枚举项进行了求和,这是不需要的,也是危险的。如果您喜欢Danger并使用旧版本的Ruby,可以将#sum添加到Array类中:

1
2
3
4
5
class Array
  def sum
    inject(0) { |sum, x| sum + x }
  end
end

然后做一些有趣的事情,比如:

1
[1, 2, 3, 4].sum


Ruby 2.4.0的新功能

您可以使用适当命名的方法Enumerable#sum。与inject(:+)相比,它有很多优点,但在最后还有一些重要的注释需要阅读。

实例范围

1
2
(1..100).sum
#=> 5050

数组

1
2
3
4
5
[1, 2, 4, 9, 2, 3].sum
#=> 21

[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7

重要注意事项

这种方法不等同于#inject(:+)。例如

1
2
3
4
%w(a b c).inject(:+)
#=>"abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer

也,

1
2
3
4
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)

有关sum为何如此的更多信息,请参阅此答案。


为了多样性起见,如果数组不是数字数组,而是具有数字属性(例如数量)的对象数组,则也可以执行此操作:

1
array.inject(0){|sum,x| sum + x.amount}


Ruby 2.4+/rails-array.sum,即[1, 2, 3].sum # => 6

Ruby Pre 2.4-array.inject(:+)array.reduce(:+)

*注:#sum方法是对enumerable的2.4的一个新添加,因此您现在可以在纯Ruby中使用array.sum,而不仅仅是Rails。


Ruby1.8.7方式如下:

1
array.inject(0, &:+)


您可以简单地使用:

1
2
    example = [1,2,3]
    example.inject(:+)


这是Enough[1,2,3].inject('+')


Ruby2.4.0发布了,它有一个Enumerable Sum方法。所以你可以这样做

1
array.sum

文档示例:

1
2
3
{ 1 => 10, 2 => 20 }.sum {|k, v| k * v }  #=> 50
(1..10).sum                               #=> 55
(1..10).sum {|v| v * 2 }                  #=> 110

还允许使用[1,2].sum{|x| x * 2 } == 6

1
2
3
4
5
6
7
8
9
10
11
12
13
# http://madeofcode.com/posts/74-ruby-core-extension-array-sum
class Array
  def sum(method = nil, &block)
    if block_given?
      raise ArgumentError,"You cannot pass a block and a method!" if method
      inject(0) { |sum, i| sum + yield(i) }
    elsif method
      inject(0) { |sum, i| sum + i.send(method) }
    else
      inject(0) { |sum, i| sum + i }
    end
  end
end

对于值为零的数组,我们可以进行压缩,然后注入和前-

1
2
a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)


1
array.reduce(:+)

也适用于范围…因此,

1
(1..10).reduce(:+) returns 55


方法1:

1
2
3
4
5
6
    [1] pry(main)> [1,2,3,4].sum
    => 10
    [2] pry(main)> [].sum
    => 0
    [3] pry(main)> [1,2,3,5,nil].sum
    TypeError: nil can't be coerced into Integer

方法2:

1
2
3
4
5
6
7
8
9
   [24] pry(main)> [].inject(:+)
   => nil
   [25] pry(main)> [].inject(0, :+)
   => 0
   [4] pry(main)> [1,2,3,4,5].inject(0, :+)
   => 15
   [5] pry(main)> [1,2,3,4,nil].inject(0, :+)
   TypeError: nil can't be coerced into Integer
   from (pry):5:in `+'

方法3:

1
2
3
4
5
6
7
   [6] pry(main)> [1,2,3].reduce(:+)
   => 6
   [9] pry(main)> [].reduce(:+)
   => nil
   [7] pry(main)> [1,2,nil].reduce(:+)
   TypeError: nil can't be coerced into Integer
   from (pry):7:in `+'

方法4:当数组包含nil和空值时,默认情况下,如果使用上述任何函数reduce、sum、inject,则所有内容都将通过

TypeError: nil can't be coerced into Integer

你可以通过

1
2
3
4
5
6
   [16] pry(main)> sum = 0
   => 0
   [17] pry(main)> [1,2,3,4,nil, ''].each{|a| sum+= a.to_i }
   => [1, 2, 3, 4, nil,""]
   [18] pry(main)> sum
   => 10

方法6:埃瓦

计算字符串中的Ruby表达式。

1
2
3
4
5
6
7
8
9
  [26] pry(main)> a = [1,3,4,5]
  => [1, 3, 4, 5]
  [27] pry(main)> eval a.join '+'
  => 13
  [30] pry(main)> a = [1,3,4,5, nil]
  => [1, 3, 4, 5, nil]
  [31] pry(main)> eval a.join '+'
  SyntaxError: (eval):1: syntax error, unexpected end-of-input
  1+3+4+5+

如果你觉得高尔基,你可以

1
eval([123,321,12389]*?+)

这将创建一个字符串"123+321+12389",然后使用函数eval进行求和。这只是打高尔夫球的目的,你不应该用正确的代码。


或者您可以尝试以下方法:

1
2
3
4
def sum arr
  0 if arr.empty
  arr.inject :+
end

这是最短的路。试试看。

array.inject :+


你也可以用简单的方法

1
2
3
4
5
6
def sum(numbers)
  return 0 if numbers.length < 1
  result = 0
  numbers.each { |num| result += num }
  result
end

您可以使用.map和.sum,如下所示:

1
array.map { |e| e }.sum