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

How to sum array of numbers in Ruby?

提问人:brainfck 提问时间:10/9/2009 最后编辑:Mab879brainfck 更新时间:9/13/2022 访问量:549525

问:

我有一个整数数组。

例如:

array = [123,321,12389]

有什么好方法可以得到它们的总和吗?

我知道那件事

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

会起作用的。

Ruby 数组数学 求和

评论

40赞 dawg 7/4/2017
请注意,Ruby 2.4+ 具有array.sum
1赞 Lori 1/23/2019
Ruby 2.6 没有它。Ruby 给了,Ruby 拿走了,似乎。
2赞 steenslag 6/26/2019
@Lori嗯?链接
2赞 Lori 6/27/2019
不好意思。当时我错误地认为我使用的是 2.6,因为我的 rbenv 失误。
0赞 Joshua Pinter 3/6/2021
如果需要在 时提供默认值,例如如果要返回对象而不是 ,则可以执行类似 的操作。ArrayMoneyIntegerarray.sum( 0.to_money( "USD" ) )

答:

646赞 zenazn 10/9/2009 #1

试试这个:

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

参见 Ruby 的 Enumerable 文档

(注意:需要基本情况,以便将其返回到空数组而不是00nil)

评论

327赞 Peter 10/9/2009
Jorney's 效率更高。array.inject(:+)
4赞 Kamil Szot 10/10/2012
array.inject(:+)似乎在 Ruby 1.8.6 中引起了麻烦,可能会弹出“LocalJumpError : no block given”异常。
37赞 Kamil Szot 10/10/2012
在 rails 中可能会给你数组值的总和。array.sum
33赞 Boris Stitnicky 4/5/2013
在大多数情况下,我更喜欢使用 ,它是 (如 中的 ) 的别名。reduceinjectarray.reduce( :+ )
3赞 yurisich 7/27/2013
@Boris 此外,Rubycop 会警告您使用 而不是 .injectreduce
861赞 jomey 10/9/2009 #2

对于 ruby >= 2.4,您可以使用 sum

array.sum

对于 ruby < 2.4,您可以使用 inject

array.inject(0, :+)

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

> [].inject(:+)
nil
> [].inject(0, :+)
0

评论

6赞 Pablo Cantero 4/28/2011
如何使用这种方式对对象中的属性求和。我的数组 [product1, product2] 我想对 product1.price + product2.price 求和。是否可以使用 array.inject(:+)?
7赞 markquezada 9/8/2011
你可以对 map 方法使用类似的技巧:array.map(&:p rice).inject(:+)
101赞 johnf 10/4/2011
array.map(&:price).inject(0, :+)更安全一点。它确保如果你有一个空列表,你会得到 0 而不是 nil
11赞 everett1992 4/4/2013
使用 array.map(...)。inject(...) 效率低下,您将遍历所有数据两次。尝试array.inject(0) { |sum, product| sum += product.price }
5赞 Cameron Martin 8/19/2014
@everett1992事实证明,根本没有优化。分两个阶段完成对我来说总是更快。gist.github.com/cameron-martin/b907ec43a9d8b9303bdc
118赞 Mike Woodhouse 10/9/2009 #3

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

require 'activesupport'
array.sum

评论

13赞 dcashman 3/22/2012
默认情况下,较新版本的 activesupport 实际上不会加载所有扩展。您要么只需要 sum 模块:,要么需要所有活动支持:。更多信息请见:API 文档require 'active_support/core_ext/enumerable.rb'require 'active_support/all'
2赞 user229044 2/11/2016
没关系,这是一个巨大的依赖关系,要拖到一个项目中去。activesupportarray.inject(:+)array.sum
1赞 Per Lundberg 7/6/2016
吹毛求疵:它应该没有后缀,因为它是隐式添加的。require 'active_support/core_ext/enumerable'.rb
97赞 jrhicks 10/9/2009 #4

对于 Ruby >=2.4.0,您可以从 Enumerables 中使用。sum

[1, 2, 3, 4].sum

mokeypatch 基类很危险。如果你喜欢危险,并且使用旧版本的 Ruby,你可以添加到类中:#sumArray

class Array
  def sum
    inject(0) { |sum, x| sum + x }
  end
end

评论

19赞 user3467349 10/5/2016
对基类进行猴子修补并不好。
2赞 Peter H. Boling 4/5/2017
他的观点是,你不需要为 Ruby >= 2.4 做 Monkey 补丁,而且 monkey 补丁是危险的,你现在可以原生求和可枚举对象,但也有一种方法可以向后移植功能。
0赞 Cary Swoveland 5/7/2018
如前所述,Enumerable#sum(和 Array#sum)是在 Ruby v2.4 中引入的。重要的是,它们的行为与您的行为不同;也就是说,它们采用可选参数和可选块。按原样定义将导致在代码中出现参数或块的任何位置引发异常。Array#sumArray#sumsum
0赞 Joshua Pinter 3/6/2021
如果需要在 时提供默认值,例如如果要返回对象而不是 ,则可以执行类似 的操作。ArrayMoneyIntegerarray.sum( 0.to_money( "USD" ) )
4赞 grosser 1/30/2011 #5

还允许:[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
18赞 Vova 6/22/2011 #6

Ruby 1.8.7 的方式如下:

array.inject(0, &:+) 

评论

0赞 Andrew Grimm 6/17/2014
如果您阅读了我 2011 年的评论,并且在您使用的是 1.8.6 时它仍然相关,请升级!
305赞 Evan 12/15/2012 #7
array.reduce(0, :+)

虽然等同于,但随着MapReduce编程模型的兴起,术语reduce正在进入一个更常见的术语。array.inject(0, :+)

injectreducefold、accumulatecompress 都是一类折叠函数的同义词。我发现代码库的一致性最为重要,但由于不同的社区倾向于更喜欢一个词而不是另一个词,因此了解替代方案仍然很有用。

为了强调 map-reduce 措辞,这里有一个版本,它对该数组中的最终内容更加宽容。

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

一些额外的相关阅读材料:

评论

12赞 everett1992 4/4/2013
我同意,告诉我更多关于该功能的作用,但听起来确实很酷。reduceinject
1赞 acjay 4/13/2015
我要说的一句话是,由于高阶函数早于 MapReduce。灵感则相反。从MapReduce的角度来看,它与简单的函数式reduce有些不同,对不同机器的通信方式有影响。reducemap
1赞 Fernando Pelliccioni 7/25/2016
肯·艾弗森(Ken Iverson)在编程语言APL中引入了算子/称为“约简算子”。资料来源:艾弗森,肯尼斯。1962. 一种编程语言。威利。另一个来源:“符号作为一种思想工具”,1979 年 ACM 图灵奖演讲,Kenneth E. Iverson,dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf
19赞 HashFail 7/24/2013 #8

只是为了多样化,如果你的数组不是数字数组,而是具有数字属性(例如金额)的对象数组,你也可以这样做:

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

评论

3赞 Richard Jones 2/21/2014
这相当于执行:。查看其他答案。array.map(&:amount).inject(0, :+)
4赞 HashFail 2/22/2014
在某种程度上,是的。但是,使用 then 需要您遍历数组两次:一次用于创建新数组,另一次用于对成员求和。这种方法稍微冗长一些,但也更有效。mapinject
0赞 rmcsharry 7/3/2019
显然它并没有更有效率,请参阅 gist.github.com/cameron-martin/b907ec43a9d8b9303bdc - 归功于此答案中的评论:stackoverflow.com/a/1538949/1028679
1赞 Cadoiz 7/28/2023
@RichardJones或截至今天(使用 ruby >= 2.4 或 rails)。array.sum(&:amount)
-1赞 Prabhakar 12/12/2014 #9

您也可以以简单的方式完成

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

评论

1赞 user229044 7/31/2020
这是非常不惯用的 Ruby,它看起来像是 C 程序员编写的 Ruby。在 Ruby 中,或者是首选。injectsum
-10赞 shabdar 7/24/2015 #10

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

array.map { |e| e }.sum

评论

3赞 Arnold Roa 12/4/2015
做一个返回相同元素的地图有什么意义?这与array.sum
22赞 typo 6/9/2016 #11

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

Ruby 2.4 之前的版本 - 或array.inject(:+)array.reduce(:+)

*注意:该方法是 2.4 的新增功能,因此您现在可以在纯 ruby 中使用,而不仅仅是 Rails。#sumenumerablearray.sum

1赞 Ulysse BN 11/28/2016 #12

如果你觉得打高尔夫球,你可以做

eval [123,321,12389]*?+

这将创建一个字符串“123+321+12389”,然后使用函数 eval 进行求和。这仅用于高尔夫目的,您不应在适当的代码中使用它。

6赞 Santhosh 12/19/2016 #13

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
51赞 Eli Sadoff 1/4/2017 #14

Ruby 2.4.0 的新功能

您可以使用恰如其分命名的方法。它有很多优点,但最后也有一些重要的注意事项需要阅读。Enumerable#suminject(:+)

例子

范围

(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)

有关为什么会这样的更多信息,请参阅此答案sum

评论

0赞 Joshua Pinter 3/6/2021
如果需要在 时提供默认值,例如如果要返回对象而不是 ,则可以执行类似 的操作。ArrayMoneyIntegerarray.sum( 0.to_money( "USD" ) )
0赞 Cadoiz 7/28/2023
此答案已弃用。例如,在 ruby2.6.6 中,你可以%w(a b c).sum # => "abc"
0赞 Kelsey Hannan 11/21/2023
请注意,如果您正在进行数学运算,则 of 或 called by 会将它们转换回 ,破坏您的数学!您需要调用以保留 Float。ArrayFloatBigDecimal.sumIntegerfoo.sum.to_f
2赞 raj_acharya 2/1/2018 #15

方法1:

    [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:

   [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:

   [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:当 Array 包含 nil 和空值时,默认情况下,如果你使用上述任何函数 reduce、sum、in注入,一切都会通过

TypeError:nil 无法强制转换为整数

你可以通过以下方式克服这个问题,

   [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:eval

计算字符串中的 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+

评论

0赞 Cadoiz 7/28/2023
reduce从字面上看是一回事。如果你真的想自己构建一个对象,你应该考虑each_with_object而不是(方法4)。建议:injecteach[1,2,3,4,nil, ''].each_with_object(0) {|a| sum+= a.to_i }
4赞 thedudecodes 5/3/2018 #16

对于具有 nil 值的数组,我们可以进行压缩,然后注入总和 前任-

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