ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个整数数组。

例如:

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,您可以执行类似 array.sum( 0.to_money( "USD" ) ) 的操作。

N
Ngoral

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

array.sum

对于红宝石 2.4您可以使用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
F
Fernando Briano

尝试这个:

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
D
David Wolever
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
M
Mike Woodhouse

或者(仅用于比较),如果您安装了 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
Nitpick 一个很好的评论:它应该是没有 .rb 后缀的 require 'active_support/core_ext/enumerable',因为它是隐式添加的。
A
Alexander Oh

对于 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 做 Monkey Patch,而且 Monkey 补丁是危险的,你现在可以原生地对 enumerables 求和,但还有一种方法可以向后移植功能。
被否决,因为您的实现在空数组上返回 nil。
C
Community

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)

有关 sum 为何如此的详细信息,请参阅 this answer


如果您需要在 Array 为空时提供默认值,例如如果您想要返回一个 Money 对象而不是 Integer,您可以执行类似 array.sum( 0.to_money( "USD" ) ) 的操作。
t
typo

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 你是对的!很高兴看到这个有用的功能包括在内。
H
HashFail

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

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

这相当于执行:array.map(&:amount).inject(0, :+)。查看其他答案。
在某种程度上,是的。但是,使用 map 然后 inject 需要您循环遍历数组两次:一次是创建一个新数组,另一次是对成员求和。这种方法略显冗长,但也更有效。
显然它效率不高,请参阅 gist.github.com/cameron-martin/b907ec43a9d8b9303bdc - 归功于此答案中的评论:stackoverflow.com/a/1538949/1028679
V
Vova

ruby 1.8.7 方式如下:

array.inject(0, &:+) 

如果您阅读了我 2011 年的评论,并且在您使用 1.8.6 时仍然适用,请升级!
S
Santhosh

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

t
thedudecodes

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

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

t
the Tin Man

还允许 [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

N
Nataraja B

方法一:

    [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 `+'

方法4:当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

方法6:评估

评估字符串中的 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+

U
Ulysse BN

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

eval [123,321,12389]*?+

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


G
Giacomo1968

你也可以用简单的方法做到这一点

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

这是一个非常不惯用的 Ruby,它看起来像是由 C 程序员编写的 Ruby。在 Ruby 中,首选 injectsum
s
shabdar

您可以使用 .map 和 .sum ,例如:

array.map { |e| e }.sum

地图返回相同元素有什么意义?这与 array.sum 完全相同
此外,ruby 中不存在 array.sum。请参阅Mike Woodhouse answer
它现在在 Ruby 2.4.0 中