如何在 Ruby 中对数字数组求和?
Posted
技术标签:
【中文标题】如何在 Ruby 中对数字数组求和?【英文标题】:How to sum array of numbers in Ruby? 【发布时间】:2010-12-05 01:23:52 【问题描述】:我有一个整数数组。
例如:
array = [123,321,12389]
有没有什么好方法可以得到它们的总和?
我知道,那
sum = 0
array.each |a| sum+=a
会起作用的。
【问题讨论】:
请注意Ruby 2.4+有array.sum
Ruby 2.6 没有它。 Ruby 给予,Ruby 带走,似乎。
@Lori 嗯? link
对不起。那时我错误地认为我使用的是 2.6,因为我的 rbenv 失误。
如果您需要在Array
为空时提供默认值,例如如果您想返回Money
对象而不是Integer
,您可以执行@987654328 之类的操作@.
【参考方案1】:
对于 ruby >= 2.4,您可以使用sum:
array.sum
对于 ruby ,您可以使用 inject:
array.inject(0, :+)
注意:0
基本情况是必需的,否则 nil
将在空数组上返回:
> [].inject(:+)
nil
> [].inject(0, :+)
0
【讨论】:
如何使用这种方式从对象中求和属性。我的数组 [product1, product2] 我想对 product1.price + product2.price 求和。是否可以使用 array.inject(:+)? 您可以在 map 方法中使用类似的技巧:array.map(&:price).inject(:+)array.map(&:price).inject(0, :+)
更安全一些。它确保如果你有一个空列表,你会得到 0 而不是 nil。
使用 array.map(...).inject(...) 效率低下,您将遍历所有数据两次。试试array.inject(0) |sum, product| sum += product.price
@everett1992 事实证明,甚至根本没有优化。分两个阶段做对我来说总是更快。 gist.github.com/cameron-martin/b907ec43a9d8b9303bdc【参考方案2】:
试试这个:
array.inject(0)|sum,x| sum + x
See Ruby's Enumerable Documentation
(注意:需要0
基本情况,以便0
将在空数组而不是nil
上返回)
【讨论】:
jorney 的array.inject(:+)
效率更高。
array.inject(:+)
似乎在 Ruby 1.8.6 中导致 麻烦 异常“LocalJumpError : no block given”可能会弹出。
在 rails array.sum
可能会给你数组值的总和。
在大多数情况下,我更喜欢使用reduce
,它是inject
的别名(如array.reduce( :+ )
)。
@Boris 另外,Rubycop 会警告你使用inject
而不是reduce
。【参考方案3】:
array.reduce(0, :+)
虽然等同于array.inject(0, :+)
,但随着MapReduce programming models 的兴起,reduce 一词正在进入更常见的术语。
inject、reduce、fold、accumulate和compress都是与folding functions 的类同义。我发现您的代码库的一致性最重要,但由于各个社区倾向于使用一个词而不是另一个词,因此了解替代词仍然很有用。
为了强调 map-reduce 的措辞,这里有一个版本,它对数组中的内容更加宽容。
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_(higher-order_function)【讨论】:
我同意,reduce
告诉我更多该函数的作用,但inject
听起来更酷。
同意最后的评论,你给了我最好的答案。
我要说的一条评论是 reduce
和 map
作为高阶函数早于 MapReduce。灵感是相反的。在 MapReduce 的意义上,它是一个与简单的函数式 reduce 有所不同的操作,对不同机器的通信方式有影响。
Ken Iverson 在 APL 编程语言中引入了运算符 / 称为“归约运算符”。资料来源:艾弗森,肯尼斯。 1962. 一种编程语言。威利。另一个来源:“作为思想工具的符号”,1979 ACM 图灵奖讲座,Kenneth E. Iverson,dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf【参考方案4】:
或者(仅用于比较),如果您安装了 Rails(实际上只是 ActiveSupport):
require 'activesupport'
array.sum
【讨论】:
较新版本的 activesupport 默认情况下实际上并不加载所有扩展。你要么只需要 sum 模块:require 'active_support/core_ext/enumerable.rb'
,要么需要所有的积极支持:require 'active_support/all'
。更多信息在这里:API Docs
别介意activesupport
是一个大量 依赖项,可以拖入项目以从array.inject(:+)
转到array.sum
。
吹毛求疵的评论:它应该是 require 'active_support/core_ext/enumerable'
没有 .rb
后缀,因为这是隐式添加的。【参考方案5】:
对于 Ruby >=2.4.0,您可以使用 Enumerables 中的 sum
。
[1, 2, 3, 4].sum
mokeypatch 基类很危险。如果你喜欢危险并使用旧版本的 Ruby,你可以将 #sum
添加到 Array
类中:
class Array
def sum
inject(0) |sum, x| sum + x
end
end
【讨论】:
请不要这样做 @user3467349 为什么? Monkeypatching 基类不好。 他的意思是你不需要为 Ruby >= 2.4 做猴子补丁,猴子补丁是危险的,你现在可以原生地对枚举进行求和,但是有也是一种向后移植功能的方法。 投反对票,因为您的实现在空数组上返回 nil。【参考方案6】:Ruby 2.4.0 的新功能
您可以使用恰当命名的方法Enumerable#sum
。它比inject(:+)
有很多优势,但最后也有一些重要的注意事项需要阅读。
示例
范围
(1..100).sum
#=> 5050
数组
[1, 2, 4, 9, 2, 3].sum
#=> 21
[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7
重要提示
此方法不等同于#inject(:+)
。例如
%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
还有,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)
请参阅this answer,了解有关sum
为何如此的更多信息。
【讨论】:
如果您需要在Array
为空时提供默认值,例如如果您想返回Money
对象而不是Integer
,您可以执行@987654333 之类的操作@.【参考方案7】:
Ruby 2.4+ / Rails - array.sum
即[1, 2, 3].sum # => 6
Ruby pre 2.4 - array.inject(:+)
或 array.reduce(:+)
*注意:#sum
方法是 2.4 对 enumerable
的新增功能,因此您现在可以在纯 ruby 中使用 array.sum
,而不仅仅是 Rails。
【讨论】:
Ruby 2.4.0 已于今天发布,其中包含此功能! ? @amoebe 你是对的!很高兴看到包含这个有用的功能。【参考方案8】:为了多样性,如果您的数组不是数字数组,而是具有数字属性(例如数量)的对象数组,您也可以这样做:
array.inject(0)|sum,x| sum + x.amount
【讨论】:
这相当于做:array.map(&:amount).inject(0, :+)
。查看其他答案。
在某种程度上,是的。但是,使用 map
然后 inject
需要您循环遍历数组两次:一次创建新数组,另一次对成员求和。这种方法稍微冗长一些,但也更有效。
显然效率不高,请参阅gist.github.com/cameron-martin/b907ec43a9d8b9303bdc - 在此答案中归功于 cmets:***.com/a/1538949/1028679【参考方案9】:
ruby 1.8.7方式如下:
array.inject(0, &:+)
【讨论】:
如果您阅读了我 2011 年的评论,并且在您使用 1.8.6 时仍然适用,请升级!【参考方案10】:Ruby 2.4.0 发布了,它有一个Enumerable#sum 方法。所以你可以做
array.sum
文档中的示例:
1 => 10, 2 => 20 .sum |k, v| k * v #=> 50
(1..10).sum #=> 55
(1..10).sum |v| v * 2 #=> 110
【讨论】:
【参考方案11】:对于具有 nil 值的数组,我们可以进行压缩,然后注入总和 前-
a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)
【讨论】:
【参考方案12】:还允许[1,2].sum|x| x * 2 == 6
:
# 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
【讨论】:
【参考方案13】:方法一:
[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
方法二:
[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 `+'
方法三:
[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 `+'
方法四: 当 Array 包含 nil 和空值时,默认情况下,如果您使用上述任何函数 reduce、sum、inject 一切都将通过
TypeError: nil 不能被强制转换为 Integer
你可以通过以下方式克服这个问题,
[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
方法六: 评估
计算字符串中的 Ruby 表达式。
[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+
【讨论】:
【参考方案14】:如果你觉得打高尔夫球,你可以这样做
eval [123,321,12389]*?+
这将创建一个字符串“123+321+12389”,然后使用函数 eval 进行求和。这仅用于打高尔夫球目的,您不应在正确的代码中使用它。
【讨论】:
【参考方案15】:你也可以轻松搞定
def sum(numbers)
return 0 if numbers.length < 1
result = 0
numbers.each |num| result += num
result
end
【讨论】:
这是一个非常不地道的 Ruby,它看起来像一个 C 程序员编写的 Ruby。在 Ruby 中,inject
或 sum
是首选。【参考方案16】:
你可以使用 .map 和 .sum 像:
array.map |e| e .sum
【讨论】:
地图返回相同元素的意义何在?这与array.sum
完全相同
此外,ruby 中不存在 array.sum。见Mike Woodhouse answer
现在在 Ruby 2.4.0 中可以使用以上是关于如何在 Ruby 中对数字数组求和?的主要内容,如果未能解决你的问题,请参考以下文章