Bir tamsayı dizim var.
Örneğin:
array = [123,321,12389]
Bunların toplamını almanın güzel bir yolu var mı?
Bunu biliyorum
sum = 0
array.each { |a| sum+=a }
çalışır.
Bir tamsayı dizim var.
Örneğin:
array = [123,321,12389]
Bunların toplamını almanın güzel bir yolu var mı?
Bunu biliyorum
sum = 0
array.each { |a| sum+=a }
çalışır.
Yanıtlar:
Bunu dene:
array.inject(0){|sum,x| sum + x }
Ruby'nin Numaralandırılabilir Belgelerine Bakın
(not: 0temel durum gereklidir, böylece 0bunun yerine boş bir dizide döndürülür nil)
array.inject(:+)daha verimlidir.
array.inject(:+)Ruby'de sorun yaratıyor gibi görünüyor 1.8.6 İstisnalar "LocalJumpError: verilen blok yok" belirebilir.
array.sumdizi değerlerinin toplamını verebilir.
reducebir takma adı olan kullanmayı tercih ederim . injectarray.reduce( :+ )
injectyerine sizi uyarır reduce.
Veya Ruby 1.9 yolunu deneyin:
array.inject(0, :+)
Not: 0temel kasa gereklidir aksi takdirde nilboş dizilerde iade edilir:
> [].inject(:+)
nil
> [].inject(0, :+)
0
array.map(&:price).inject(0, :+)biraz daha güvenlidir. Boş bir listeniz varsa nil yerine 0 almanızı sağlar .
array.inject(0) { |sum, product| sum += product.price }
array.reduce(0, :+)
Buna eşit olmakla birlikte array.inject(0, :+), azaltma terimi MapReduce programlama modellerinin yükselişiyle daha yaygın bir yerel dile giriyor .
enjekte etme , azaltma , katlama , biriktirme ve sıkıştırma , katlama işlevleri sınıfı olarak eşanlamlıdır . Kod tabanınızdaki tutarlılığı en önemli buluyorum, ancak çeşitli topluluklar bir kelimeyi diğerine tercih etme eğiliminde olduğundan, alternatifleri bilmek yararlıdır.
Harita azaltma ayrıntılarını vurgulamak için, bu dizide neyin bittiği konusunda biraz daha affedici bir sürüm.
array.map(&:to_i).reduce(0, :+)
İlgili ek okumalar:
reducebana işlevin ne yaptığından daha fazlasını anlatıyor, ama injectkulağa daha havalı geliyor.
reduceve mapüst düzey işlevler MapReduce'dan önce gelir. İlham başka bir şekilde ilerliyor. MapReduce anlamında, farklı makinelerin nasıl iletişim kurdukları üzerinde çıkarımları olan basit bir işlevsel azaltma işleminden biraz farklı bir işlemdir.
Alternatif olarak (yalnızca karşılaştırma için), Rails yüklüyse (aslında sadece ActiveSupport):
require 'activesupport'
array.sum
require 'active_support/core_ext/enumerable.rb'ya da aktif desteğinin tüm gerektirir: require 'active_support/all'. Daha fazlası için: API Docs
activesupportiçin büyük bir bağımlılık olduğunu aklınızdan array.inject(:+)çıkarmayın array.sum.
require 'active_support/core_ext/enumerable', .rbsonek olmadan olmalıdır .
Ruby> = 2.4.0 sumiçin Numaralandırıcılar'dan kullanabilirsiniz .
[1, 2, 3, 4].sum
Mokeypatch temel sınıfları tehlikelidir. Eğer tehlikeyi ve Ruby eski bir sürümünü kullanıyor isterseniz, ekleyebilirsiniz #sumiçin Arraysınıfın:
class Array
def sum
inject(0) { |sum, x| sum + x }
end
end
Uygun şekilde adlandırılmış yöntemi kullanabilirsiniz Enumerable#sum. Çok fazla avantajı var inject(:+)ama sonunda okunması gereken bazı önemli notlar da var.
(1..100).sum
#=> 5050
[1, 2, 4, 9, 2, 3].sum
#=> 21
[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7
Bu yöntem eşdeğer değildir #inject(:+). Örneğin
%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
Ayrıca,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)
Neden böyle olduğu hakkında daha fazla bilgi için bu cevaba bakınız sum.
Ruby 2.4+ / Raylar - array.sumie[1, 2, 3].sum # => 6
Ruby pre 2.4 - array.inject(:+)veyaarray.reduce(:+)
* Not: #sumYöntem 2.4 için yeni bir ektir, enumerablebu yüzden artık array.sumsadece Rails değil, saf yakutta da kullanabileceksiniz .
Sadece çeşitlilik uğruna, diziniz bir sayı dizisi değil, sayı olan özelliklere sahip nesneler dizisi (örneğin miktar) ise bunu da yapabilirsiniz:
array.inject(0){|sum,x| sum + x.amount}
array.map(&:amount).inject(0, :+). Diğer cevaplara bakın.
mapdaha sonra kullanmak injectdizi boyunca iki kez döngü yapmanızı gerektirir: bir kez yeni bir dizi oluşturmak için, diğeri üyeleri toplamak için. Bu yöntem biraz daha ayrıntılı, ancak aynı zamanda daha verimlidir.
yakut 1.8.7 yolu aşağıdaki gibidir:
array.inject(0, &:+)
Sadece şunu kullanabilirsiniz:
example = [1,2,3]
example.inject(:+)
inject(:+)ama bu işe yaramıyor inject :+?
Bu yeterli
[1,2,3].inject('+')
Ruby 2.4.0 yayınlandı ve Enumerable # sum yöntemi var. Böylece yapabilirsin
array.sum
Dokümanlardan örnekler:
{ 1 => 10, 2 => 20 }.sum {|k, v| k * v } #=> 50
(1..10).sum #=> 55
(1..10).sum {|v| v * 2 } #=> 110
Ayrıca [1,2].sum{|x| x * 2 } == 6şunları sağlar :
# 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
sıfır değerli diziler için kompakt yapabiliriz ve sonra toplamı enjekte edebiliriz.
a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)
Yöntem 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
Yöntem 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 `+'
Yöntem 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 `+'
Yöntem 4: Dizi nil ve boş değerler içerdiğinde, varsayılan olarak yukarıdaki işlevleri kullanırsanız, her şeyi kullanarak
TypeError: nil Tamsayıya zorlanamaz
Bunun üstesinden gelebilirsiniz,
[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
Yöntem 6: Eval
Dize içindeki Ruby ifadelerini değerlendirir.
[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+
Bu en kısa yol. Dene.
array.inject :+
number = [1..100]
number. each do |n|
final_number = n.sum
puts "The sum is #{final_number}"
end
* Bu yeni bir geliştirici olarak benim için iyi çalıştı. Sayı aralığınızı [] içindeki değerleri değiştirerek ayarlayabilirsiniz
Kolayca da yapabilirsiniz
def sum(numbers)
return 0 if numbers.length < 1
result = 0
numbers.each { |num| result += num }
result
end
.Map ve .sum gibi kullanabilirsiniz :
array.map { |e| e }.sum
array.sum
array.sum