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: 0
temel durum gereklidir, böylece 0
bunun 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.sum
dizi değerlerinin toplamını verebilir.
reduce
bir takma adı olan kullanmayı tercih ederim . inject
array.reduce( :+ )
inject
yerine sizi uyarır reduce
.
Veya Ruby 1.9 yolunu deneyin:
array.inject(0, :+)
Not: 0
temel kasa gereklidir aksi takdirde nil
boş 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:
reduce
bana işlevin ne yaptığından daha fazlasını anlatıyor, ama inject
kulağa daha havalı geliyor.
reduce
ve 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
activesupport
iç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'
, .rb
sonek olmadan olmalıdır .
Ruby> = 2.4.0 sum
iç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 #sum
için Array
sı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.sum
ie[1, 2, 3].sum # => 6
Ruby pre 2.4 - array.inject(:+)
veyaarray.reduce(:+)
* Not: #sum
Yöntem 2.4 için yeni bir ektir, enumerable
bu yüzden artık array.sum
sadece 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.
map
daha sonra kullanmak inject
dizi 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