[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
Bu koda bakıyorum ama beynim 10 numara nasıl sonuç olabilir kayıt değil. Burada neler olduğunu açıklayan biri olur mu?
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
Bu koda bakıyorum ama beynim 10 numara nasıl sonuç olabilir kayıt değil. Burada neler olduğunu açıklayan biri olur mu?
Yanıtlar:
İlk blok argümanını bir akümülatör olarak düşünebilirsiniz: bloğun her çalışmasının sonucu akümülatörde saklanır ve daha sonra bloğun bir sonraki yürütülmesine geçirilir. Yukarıda gösterilen kod durumunda, akümülatörü varsayılan olarak 0 olarak ayarlarsınız. Bloğun her çalıştırılması, verilen sayıyı geçerli toplama ekler ve ardından sonucu tekrar akümülatöre kaydeder. Bir sonraki blok çağrısı bu yeni değere sahiptir, ekler, tekrar saklar ve tekrar eder.
İşlemin sonunda, enjekte edin, bu durumda dizideki veya 10'daki tüm değerlerin toplamı olan akümülatörü döndürür.
Aşağıda, dize temsilleriyle anahtarlanan bir nesne dizisinden karma oluşturmak için başka bir basit örnek verilmiştir:
[1,"a",Object.new,:hi].inject({}) do |hash, item|
hash[item.to_s] = item
hash
end
Bu durumda, akümülatörümüzü varsayılan olarak boş bir karmaya ayarlıyoruz, ardından blok her yürütüldüğünde dolduruyoruz. Karmanın bloğun son satırı olarak geri dönmesi gerektiğine dikkat edin, çünkü bloğun sonucu akümülatörde saklanacaktır.
result + explanation
hem akümülatöre dönüşüm hem de dönüş değeridir. Bloktaki son satır, onu örtük bir dönüş haline getirir.
inject
ile başlamak için bir değer ( 0
örneğin örnekte) ve bir blok alır ve bu bloğu listenin her öğesi için bir kez çalıştırır.
result + element
).Bunu açıklamanın en kolay yolu, örneğin her adımın nasıl çalıştığını göstermek olabilir; bu, bu sonucun nasıl değerlendirilebileceğini gösteren hayali bir dizi adımdır:
[1, 2, 3, 4].inject(0) { |result, element| result + element }
[2, 3, 4].inject(0 + 1) { |result, element| result + element }
[3, 4].inject((0 + 1) + 2) { |result, element| result + element }
[4].inject(((0 + 1) + 2) + 3) { |result, element| result + element }
[].inject((((0 + 1) + 2) + 3) + 4) { |result, element| result + element }
(((0 + 1) + 2) + 3) + 4
10
İnject yönteminin sözdizimi aşağıdaki gibidir:
inject (value_initial) { |result_memo, object| block }
Yukarıdaki örneği çözelim yani
[1, 2, 3, 4].inject(0) { |result, element| result + element }
bu da 10'u çıktı olarak verir .
Başlamadan önce, her bir değişkente depolanan değerlerin neler olduğunu görelim:
sonuç = 0 Sıfır , 0 olan enjekte (değer) geldi
element = 1 Dizinin ilk elemanıdır.
Tamam mı!!! Şimdi yukarıdaki örneği anlamaya başlayalım
Aşama 1 [1, 2, 3, 4].inject(0) { |0, 1| 0 + 1 }
Adım 2 [1, 2, 3, 4].inject(0) { |1, 2| 1 + 2 }
Aşama 3 [1, 2, 3, 4].inject(0) { |3, 3| 3 + 3 }
Adım: 4 [1, 2, 3, 4].inject(0) { |6, 4| 6 + 4 }
Adım 5 [1, 2, 3, 4].inject(0) { |10, Now no elements left in the array, so it'll return 10 from this step| }
Burada Kalın-İtalik değerler diziden getirilen öğelerdir ve basitçe Kalın değerler elde edilen değerlerdir.
Umarım #inject
yönteminin çalışmasını anlarsınız #ruby
.
Kod, dizideki dört öğe üzerinde yinelenir ve önceki öğeyi geçerli öğeye ekler:
Ne söylediler, ancak her zaman bir "başlangıç değeri" sağlamanız gerekmediğini unutmayın:
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
aynıdır
[1, 2, 3, 4].inject { |result, element| result + element } # => 10
Deneyin, bekleyeceğim.
Enjekte etmek için hiçbir argüman geçirilmediğinde, ilk iki öğe ilk yinelemeye geçirilir. Yukarıdaki örnekte, sonuç 1 ve eleman ilk kez 2'dir, böylece bloğa daha az bir çağrı yapılır.
Enjekte () içine koyduğunuz sayı bir başlangıç noktasını temsil eder, 0 veya 1000 olabilir. Boruların içinde iki yer tutucunuz vardır | x, y |. x = .inject ('x') içinde herhangi bir sayıya sahip olduğunuzda ve ikincil, nesnenizin her yinelemesini temsil eder.
[1, 2, 3, 4].inject(5) { |result, element| result + element } # => 15
1 + 5 = 6 2 + 6 = 8 3 + 8 = 11 11 + 4 = 15
Inject bloğu uygular
result + element
dizideki her öğeye. Sonraki öğe için ("eleman"), bloktan döndürülen değer "sonuç" dur. Onu "parametre" olarak adlandırdığınız şekilde, "sonuç" o parametrenin değeriyle başlar. Sonuç olarak efekt unsurları arttırıyor.
TLDR; önemli bir şekilde inject
farklılık gösterir map
: inject
bloğun son yürütme değerini map
döndürürken, yinelediği diziyi döndürür.
Bundan daha fazla her blok yürütme değeri ilk parametre ( result
bu durumda) aracılığıyla bir sonraki yürütmeye geçti ve bu değeri ( (0)
parça) başlatabilirsiniz .
Yukarıdaki örneğiniz şu şekilde yazılabilir map
:
result = 0 # initialize result
[1, 2, 3, 4].map { |element| result += element }
# result => 10
Aynı etki ama inject
burada daha özlü.
Genellikle ödevin map
blokta gerçekleştiğini görürsünüz, öte yandan blokta bir değerlendirme gerçekleşir inject
.
Hangi yöntemi seçtiğiniz, istediğiniz kapsama bağlıdır result
. Ne zaman için değil böyle bir şey olurdu kullanın:
result = [1, 2, 3, 4].inject(0) { |x, element| x + element }
Hepiniz gibi olabilirsiniz, "Lookie me, hepsini tek bir satırda birleştirdim", ama aynı zamanda geçici x
olarak zaten result
çalışmak zorunda olduğunuz için gerekli olmayan bir sıfırdan değişken olarak bellek ayırdınız .
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
aşağıdakine eşdeğerdir:
def my_function(r, e)
r+e
end
a = [1, 2, 3, 4]
result = 0
a.each do |value|
result = my_function(result, value)
end
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
Düz İngilizce'de, bu dizi ( [1,2,3,4]
) üzerinden (yineleme) geçiyorsunuz . 4 dizi (1, 2, 3 ve 4) olduğu için bu diziyi 4 kez yineleyeceksiniz. Enject yönteminde 1 bağımsız değişken (0 sayısı) vardır ve bu bağımsız değişkeni 1. öğeye (0 + 1 eklersiniz. Bu 1'e eşittir). 1, "sonuca" kaydedilir. Daha sonra bu sonucu (1 olan) sonraki öğeye (1 + 2) eklersiniz. Bu 3'tür). Bu artık sonuç olarak kaydedilecektir. Devam et: 3 + 3 6'ya eşit ve son olarak 6 + 4 10'a eşit.
Bu kod bir başlangıç değeri geçmeme olasılığına izin vermez, ancak neler olduğunu açıklamaya yardımcı olabilir.
def incomplete_inject(enumerable, result)
enumerable.each do |item|
result = yield(result, item)
end
result
end
incomplete_inject([1,2,3,4], 0) {|result, item| result + item} # => 10
Buradan başlayın ve blok alan tüm yöntemleri gözden geçirin. http://ruby-doc.org/core-2.3.3/Enumerable.html#method-i-inject
Sizi şaşırtan blok mu yoksa yöntemde neden bir değeriniz var? İyi soru olsa. Orada operatör yöntemi nedir?
result.+
Ne olarak başlar?
#inject(0)
Bunu yapabiliriz?
[1, 2, 3, 4].inject(0) { |result, element| result.+ element }
Bu çalışıyor mu?
[1, 2, 3, 4].inject() { |result = 0, element| result.+ element }
Gördüğünüz gibi, sadece dizinin tüm öğelerini topladığını ve dokümanlarda gördüğünüz notta bir sayı verdiğini düşünüyorum.
Bunu her zaman yapabilirsin
[1, 2, 3, 4].each { |element| p element }
dizi numaralandırılması görmek için yinelenen. Temel fikir budur.
Sadece enjekte veya azaltmak size gönderilen bir not veya akümülatör verir.
Sonuç almaya çalışabiliriz
[1, 2, 3, 4].each { |result = 0, element| result + element }
ama hiçbir şey geri gelmediği için bu eskisi gibi değil
[1, 2, 3, 4].each { |result = 0, element| p result + element }
eleman denetçi bloğunda.
Bu basit ve anlaşılması oldukça kolay bir açıklamadır:
Başlangıçta biraz kafa karıştırıcı olduğu için "başlangıç değerini" unutun.
> [1,2,3,4].inject{|a,b| a+b}
=> 10
Yukarıdakileri şu şekilde anlayabilirsiniz: 1,2,3,4 arasında bir "ekleme makinesi" enjekte ediyorum. Yani, 1 ♫ 2 ♫ 3 ♫ 4 ve ♫ bir ekleme makinesidir, bu yüzden 1 + 2 + 3 + 4 ile aynıdır ve 10'dur.
Aslında +
aralarına bir enjekte edebilirsiniz:
> [1,2,3,4].inject(:+)
=> 10
ve +
1, 2, 3 + 4 yaparak 1,2,3,4 arasında bir enjeksiyon yapın ve 10'dur. :+
Ruby'nin +
bir sembol şeklinde belirtme şeklidir.
Bu anlaşılması oldukça kolay ve sezgisel. Ve nasıl adım adım çalıştığını analiz etmek istiyorsanız, şuna benzer: 1 ve 2 almak ve şimdi onları ekleyin ve bir sonucunuz olduğunda önce saklayın (3'tür) ve şimdi, saklanır değer 3 ve dizi öğesi 3, 6 olan a + b işleminden geçer ve şimdi bu değeri depolar ve şimdi 6 ve 4, a + b işleminden geçer ve 10'dur.
((1 + 2) + 3) + 4
"Başlangıç değeri" 0
sadece başlangıç için bir "temel" dir. Çoğu durumda, buna ihtiyacınız yoktur. 1 * 2 * 3 * 4'e ihtiyacınız varsa hayal edin ve
[1,2,3,4].inject(:*)
=> 24
ve yapılır. Her 1
şeyi ile çarpmak için "başlangıç değerine" ihtiyacınız yoktur 1
.
Başka bir .inject () yöntemi biçimi var. Çok yararlıdır [4,5] .inject (&: +) Bu alanın tüm öğelerini toplar