2016-03-31 8 views
-3

Şimdiye kadar söyleyebilirim, array.reject ve array.select hiçbir şey: Ben yazmaya çalışıyordum kodu içinRuby'de, bir blok olmadan array.reject veya array.select ne yapar?

[nil, false, true].reject # Should have been reject.to_a for this example. 
=> [nil, false, true] 
[nil, false, true].select # Should have been select.to_a for this example. 
=> [nil, false, true] 

, compact ne gerekli, ama çok merak ediyorum neden reject ve select bir blok olmadan Hiçbir şey yapmayın - { |e| e } varsayılan bloğunu bekliyordum, böylece rejectcompact olur ve 'select' biraz garip anti-compact olurdu.

Varsayılan blok ne yapıyor?


Düzenleme: Üzgünüm, tembel değerlendirme çeşit tetikleyebilir ve/select numaralandırma reddetmek yararlı bir şeyler yapmak yapmak umuyordum yukarıdaki ifadelerin uçlarında, üzerine '.to_a' kapalı kaçırdı. Bu tür şeylerden kaçınmak için normal olarak & notalarımı örneklerim.

+6

[Enumerator] döndürür (http://ruby-doc.org/core-2.1.5/Enumerator.html) – fl00r

+1

irb'm içinde, [nil, false, true] .reject => # reddet. –

+1

Bloksuz seç, tıpkı dokümanlar gibi, bir numaralayıcı döndürür; Orijinal diziden başka bir şey olmasını neden beklediğinden emin değilim. Hiçbir reddetme kriteri olmadan 'reddetmenin' neden orijinal diziden başka bir şey olamayacağını anlamıyorum - bir unsuru reddetmek için hiçbir neden yoksa, neden 'kompakt' olur? –

cevap

2

bir blok birçok Ruby yöntemleri için isteğe bağlıdır. Blok verilmediğinde, bir sayım genellikle iade edilir. Bir numaralayıcı isteyebileceğiniz en az birkaç sebep vardır.

# 1 Sayımı, Enumerator sınıfındaki yöntemlerle kullanın.

İşte bir örnek. Dize içindeki harflerin durumunu değiştirmek istediğinizi varsayalım.

"oh happy day".each_char.with_index.map { |c,i| i.odd? ? c.upcase : c.downcase }.join 
    #=> "oH HaPpY DaY" 

ancak bunun yerine yazabilirsiniz: Tek alışılmış şeklidir

enum = [:odd, :even].cycle 
"oh happy day".each_char.map { |c| enum.next==:odd ? c.upcase : c.downcase }.join 

ya da belki

enum = [:upcase, :downcase].cycle 
"oh happy day".each_char.map { |c| c.send(enum.next) }.join 

Array#cycle ve Enumerator#next belgelerine bakınız. Zincir yöntemlerine

# 2 Kullanım enumerator'ın yukarıdaki ilk örnekte

yazdım:

"oh happy day".each_char.with_index.map... 

Eğer iki yöntem olabileceğini göreceksiniz Enumerator#with_indexString#each_char için dokümanlar incelemek ve varsa bloklu veya bloksuz olarak kullanılır. Burada her ikisi de bloksuz kullanılır. Bu, üç yöntemin zincirleme olmasını sağlar.

Aşağıdakilerde dönüş değerlerini inceleyin.

enum0 = "oh happy day".each_char 
    #=> #<Enumerator: "oh happy day":each_char> 
enum1 = enum0.with_index 
    #=> #<Enumerator: #<Enumerator: "oh happy day":each_char>:with_index> 
enum2 = enum1.map 
    #=> #<Enumerator: #<Enumerator: #<Enumerator: 
    #  "oh happy day":each_char>:with_index>:map> 

Sen "bileşik" Enumerator'lar olarak enum1 ve enum2 düşünmek isteyebilirsiniz.

[nil, false, true].reject 

olmak:

Sen dönüş değeri göstermek

#=> [nil, false, true] 

ama bu doğru değil. biz yazarsanız

#<Enumerator: [nil, false, true]:reject> 

: dönüş değeridir sonra

enum = [nil, false, true].reject 

:

enum.each { |e| e } 
    #=> [nil, false] 

(ki, Yakut v2.3 beri, biz enum.reject(&:itself) yazabilirsiniz). Bu, 'u çağırmak için enum1 nedenine neden olan Enumerator#each yöntemini kullanır; çünkü reject alıcısı, sınıfın sınıfının bir örneğidir.

+0

Böyle bir tam yanıt için, özellikle reddetme numaralandırmasıyla ilgili ince noktanın yaratılış noktasından ayrı bir blok tarafından çalıştırıldığından emin olun. Zincirleme deyimini oldukça sık kullanıyorum, ancak "noktaların arasında" hangi türlerin çalıştırıldığını düşünmemiştim. (Kendimi “.each {| e | e}” yazarken rütbe bulduğumu buluyorum, ancak maymun-yamadan nefret ediyorum, bu yüzden sadece gelecekteki bir versiyonunda tanımlanmış bir '.it 'yöntemi gibi bir şey için uğraşmak zorunda kalacağım. Ruby. :) –

+0

@ android.weasel \t Neden ".each {| e |" yazdınız e} ' –

2

bunun bir Enumerator yapar:

en = [1,2,3].reject 
# => #<Enumerator: [1, 2, 3]:reject> 
en.each{|n| n == 1} 
# => [2, 3] 
+0

olarak döndürdü. Haklısınız. Normalde örneklerimi kopyalayıp yapıştırırım, ama o zaman yapmadım. Bana kafa karıştırıcı olan şey, numaralamanın yararlı bir şey yapmaya zorlanmaya çalışılmasıdır. .to_a kullanarak, tüm değerleri geri vermişti, hiçbir yerde bir reddetme olmaksızın. @ CarySwoveland'ın yanıtı, yararlı bir şey yapmasını sağlamak için her bir {| e | e} ile yinelenmesi gerektiğini gösteriyor. Bu, ne yaptığımı açıkladım, ancak neden (hala) açık varsayılan davranış gibi görünmediğini anlamadan ' elde etme. –