如何在 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 一词正在进入更常见的术语。

injectreducefoldaccumulatecompress都是与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 听起来更酷。 同意最后的评论,你给了我最好的答案。 我要说的一条评论是 reducemap 作为高阶函数早于 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 中,injectsum 是首选。【参考方案16】:

你可以使用 .map.sum 像:

array.map  |e| e .sum

【讨论】:

地图返回相同元素的意义何在?这与array.sum 完全相同 此外,ruby 中不存在 array.sum。见Mike Woodhouse answer 现在在 Ruby 2.4.0 中可以使用

以上是关于如何在 Ruby 中对数字数组求和?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Postgresql 中对 JSONB 数组中的值求和?

如何在 C/C++ 中对二维数组求和

如何在 SQL 中对多列求和

如何在Ruby中的Array类中对数组的每个元素进行平方?

在单次迭代中对两个数组求和

在c#中对字节数组表示的Int32求和