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, :+) |
注:需要
1 2 3 4 | > [].inject(:+) nil > [].inject(0, :+) 0 |
试试这个:
1 | array.inject(0){|sum,x| sum + x } |
参见Ruby的可枚举文档
(注:需要
1 | array.reduce(0, :+) |
虽然与
注入、减少、折叠、积累和压缩都是一类折叠功能的同义词。我发现跨代码库的一致性最重要,但是由于不同的社区倾向于使用一个词而不是另一个词,因此了解替代词仍然很有用。
为了强调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,可以将
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的新功能
您可以使用适当命名的方法
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 |
重要注意事项
这种方法不等同于
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) |
有关
为了多样性起见,如果数组不是数字数组,而是具有数字属性(例如数量)的对象数组,则也可以执行此操作:
1 | array.inject(0){|sum,x| sum + x.amount} |
Ruby 2.4+/rails-
Ruby Pre 2.4-
*注:
Ruby1.8.7方式如下:
1 | array.inject(0, &:+) |
您可以简单地使用:
1 2 | example = [1,2,3] example.inject(:+) |
这是Enough
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 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 |
这是最短的路。试试看。
你也可以用简单的方法
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 |