Ich habe eine Reihe von ganzen Zahlen.
Zum Beispiel:
array = [123,321,12389]
Gibt es eine nette Möglichkeit, die Summe von ihnen zu erhalten?
Ich weiß das
sum = 0
array.each { |a| sum+=a }
würde funktionieren.
Versuche dies:
array.inject(0){|sum,x| sum + x }
Siehe Ruby's Enumerable Documentation
(Hinweis: Der Basisfall 0
wird benötigt, damit 0
in einem leeren Array anstelle von nil
zurückgegeben wird.)
Oder probieren Sie den Ruby 1.9-Weg:
array.inject(0, :+)
Hinweis: Der Grundfall 0
wird benötigt, andernfalls nil
wird auf leeren Arrays zurückgegeben:
> [].inject(:+)
nil
> [].inject(0, :+)
0
array.reduce(0, :+)
Während array.inject(0, :+)
entspricht, wird der Begriff redu mit dem Aufkommen von MapReduce-Programmiermodellen allgemeiner .
injizieren , reduzieren , falten , akkumulieren und komprimieren sind alle auch eine klasse von faltfunktionen . Ich finde die Konsistenz in Ihrer Codebasis am wichtigsten, aber da verschiedene Communities dazu neigen, ein Wort einem anderen vorzuziehen, ist es dennoch nützlich, die Alternativen zu kennen.
Um die kartenreduzierte Ausdrucksweise hervorzuheben, finden Sie hier eine Version, die etwas mehr darüber nachdenkt, was in diesem Array landet.
array.map(&:to_i).reduce(0, :+)
Einige zusätzliche relevante Lektüre:
Alternativ (nur zum Vergleich), wenn Sie Rails installiert haben (eigentlich nur ActiveSupport):
require 'activesupport'
array.sum
Für Ruby> = 2.4.0 können Sie sum
aus Enumerables verwenden.
[1, 2, 3, 4].sum
Es ist gefährlich, Basisklassen zu mokeypatchen. Wenn Sie Gefahr mögen und eine ältere Version von Ruby verwenden, können Sie #sum
zur Klasse Array
hinzufügen:
class Array
def sum
inject(0) { |sum, x| sum + x }
end
end
Sie können die treffend benannte Methode Enumerable#sum
verwenden. Es hat viele Vorteile gegenüber inject(:+)
, aber es gibt auch einige wichtige Hinweise, die Sie am Ende lesen sollten.
(1..100).sum
#=> 5050
[1, 2, 4, 9, 2, 3].sum
#=> 21
[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7
Diese Methode entspricht nicht #inject(:+)
. Zum Beispiel
%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
Ebenfalls,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)
Siehe diese Antwort für weitere Informationen darüber, warum sum
so ist.
Ruby 2.4+/Rails - array.sum
, d. H. [1, 2, 3].sum # => 6
Ruby vor 2.4 - array.inject(:+)
oder array.reduce(:+)
* Hinweis: Die #sum
-Methode ist eine neue Ergänzung zu 2.4 für enumerable
, sodass Sie jetzt array.sum
in reinem Ruby verwenden können, nicht nur in Rails.
Nur aus Gründen der Vielfalt können Sie dies auch tun, wenn es sich bei Ihrem Array nicht um ein Array von Zahlen handelt, sondern um ein Array von Objekten, deren Eigenschaften Zahlen sind (z. B. Betrag):
array.inject(0){|sum,x| sum + x.amount}
Ruby 1.8.7 Weg ist der folgende:
array.inject(0, &:+)
Sie können einfach verwenden:
example = [1,2,3]
example.inject(:+)
Das ist genug [1,2,3].inject('+')
Ruby 2.4.0 wird veröffentlicht und enthält die Methode Enumerable # sum . Also kannst du es tun
array.sum
Beispiele aus den Dokumenten:
{ 1 => 10, 2 => 20 }.sum {|k, v| k * v } #=> 50
(1..10).sum #=> 55
(1..10).sum {|v| v * 2 } #=> 110
Ermöglicht auch [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
für ein Array mit Nullwerten können wir kompakt machen und dann die Summe
a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)
array.reduce(:+)
Funktioniert auch für Ranges ... daher
(1..10).reduce(:+) returns 55
Methode 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
Methode 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 `+'
Methode 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 `+'
Methode 4: Wenn das Array null und leere Werte enthält, reduzieren, summieren und injizieren Sie bei Verwendung der oben genannten Funktionen standardmäßig alle Werte
TypeError: nil kann nicht in Integer umgewandelt werden
Sie können dies überwinden, indem Sie
[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
Methode 6:eval
Wertet die Ruby Ausdrücke in Zeichenfolge aus.
[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+
Wenn Sie sich golfen fühlen, können Sie es tun
eval([123,321,12389]*?+)
Dadurch wird eine Zeichenfolge "123 + 321 + 12389" erstellt und anschließend mit der Funktion eval die Summe berechnet. Das ist nur zum Golfen, du solltest es nicht im richtigen Code benutzen.
Oder Sie können diese Methode ausprobieren:
def sum arr
0 if arr.empty
arr.inject :+
end
number = [1..100]
number. each do |n|
final_number = n.sum
puts "The sum is #{final_number}"
end
* Das hat für mich als neuen Entwickler gut funktioniert. Sie können Ihren Nummernkreis anpassen, indem Sie die Werte in [] ändern.
Dies ist der kürzeste Weg. Versuch es.
array.inject :+