Ruby'de bir değişkenin Karma mı yoksa Dizi mi olduğunu söylemenin zarif bir yolu nedir?


141

Ne @some_varolduğunu kontrol etmek için,

if @some_var.class.to_s == 'Hash' 

Eminim @some_vara Hashveya an olup olmadığını kontrol etmenin daha zarif bir yolu vardır Array.


1
Andrew: Ben bir API çağırıyorum ve JSON geri almak, birden fazla sonuç varsa bir Array olsun ama sadece bir varsa ben tek bir eleman Array yerine bir karma alırsınız. Array vs Hash kontrolü yapmaktan daha iyi bir ileri var mı?
Mart'ta

2
Alacağınız ya Yani [result_hash, another_result_hash]ya single_result_hash? Bu API'yı oluşturan kişi iyi bir iş çıkarmadı!
Andrew Grimm

2
Haklısın, Andrew ve bahse girerim , API'yı yazan kişilerin bir diziye karşı bir karma test etmek yerine onu düzeltmesini sağlamak çok daha kolaydır.
Olivier 'Ölbaum' Scherler

@ drhyde ile aynı duruma sahibim. Benim durumumda 3. taraf, bir XML dosyasını ayrıştırdıktan sonra bir öğenin 1-n çocuğu olabileceği bir durumu ele almanın en iyi yoluna karar vermenin bir yolu olmayan HTTParty'dir.
Kirli Henry

Avdi Grimms ekran görüntüsünü izlemelisiniz : rubytapas.com/2016/10/17/episode-451-advanced-class-membership ve muhtemelen kaboların kabul edilene cevap vermesini sağlamalısınız.
Alexander Presber

Yanıtlar:


263

Sadece şunları yapabilirsiniz:

@some_var.class == Hash

ya da şöyle bir şey:

@some_var.is_a?(Hash)

"İs_a?" sınıf nesneler soy ağacında herhangi bir yerde ise yöntem doğrudur. Örneğin:

@some_var.is_a?(Object)  # => true

@some_var, Object öğesinden kaynaklanan bir karma veya başka bir sınıf örneği ise yukarıdakiler doğrudur. Yani, sınıf türünde katı bir eşleşme istiyorsanız, == veya instance_of? yöntem muhtemelen aradığınız şeydir.


20
is_a?truealt sınıflar için de döndüğü için en iyi seçenektir .
Fábio Batista

Ve elbette, parantezleri de bırakıyorsunuz, bu yüzden de @som_var.is_a? Hashçalışıyor :)
Gus Shortz

7
Dikkatli olun, eğer birisi size ActiveSupport :: HashWithIndifferentAccess örneğini iletirse bu sizi gerçekten şaşırtabilir. Bu bir karma gibi yanıt verir, ama aslında bir karma değildir. :(
14'te çiçeklenme

Ayrıca orijinal yazarın bir tür kontrol yapmanın yakut bir yolunu aradığı için ördek yazmayla ilgili daha fazla cevabın daha fazla olmasını isterdim.
NobodysNightmare

3
@ unflores Hash'den ActiveSupport::HashWithIndifferentAccessmiras alır, bu nedenle @some_var.is_a?(Hash)bu durumda da doğru döner. (Ben sadece aynı soru ve HashWithIndifferentAccess davası vardı ve yorumunuzdan biraz karıştı ... bu yüzden açıklığa kavuşturmak istedim)
Stilzk1n

38

Her şeyden önce, gerçek soru için en iyi cevap

Hash === @some_var

Ancak soru, burada ördek yazmanın nasıl yapılacağını göstererek gerçekten cevaplanmış olmalıydı. Bu biraz ne tür bir ördek ihtiyacınız bağlıdır.

@some_var.respond_to?(:each_pair)

veya

@some_var.respond_to?(:has_key?)

ya da

@some_var.respond_to?(:to_hash)

uygulamaya bağlı olarak doğru olabilir.


25

Genellikle "tip" ararken yakut aslında "ördek tipi" ya da "ördek ördek gibi mi?" Belirli bir yönteme yanıt verip vermediğini görürsünüz:

@some_var.respond_to?(:each)

@Some_var üzerinden yineleyebilirsiniz, çünkü her yanıt verir: her biri

Gerçekten türü bilmek istiyorsanız ve Hash veya Array ise şunları yapabilirsiniz:

["Hash", "Array"].include?(@some_var.class)  #=> check both through instance class
@some_var.kind_of?(Hash)    #=> to check each at once
@some_var.is_a?(Array)   #=> same as kind_of

Kodunuz verilerin sırasına bağlıysa (örn. Each_with_index kullanıyorsanız) bu işe yaramaz. Öğelerin sırası karma ve diziler arasında farklı uygulanır ve yakut versiyonları arasında farklıdır (. İntertwingly.net/slides/2008/oscon/ruby19/22 )
juan2raid

1
@ juan2raid: Sipariş önemliyse, sortönce onu arayın .
Andrew Grimm

İkinci örnekte @Brandon dizeye sınıfı dönüştürmek gerekir <br/>.["Hash", "Array"].include?(@some_var.class.to_s) #=> check both through instance class
OBCENEIKON

12
Hash === @some_var #=> return Boolean

bu durum vaka ifadesiyle de kullanılabilir

case @some_var
when Hash
   ...
when Array
   ...
end

4

Bunu kullanıyorum:

@var.respond_to?(:keys)

Hash ve ActiveSupport :: HashWithIndifferentAccess için çalışır.


4

Pratikte, genellikle bir değişkenin sadece bir dizi mi yoksa bir karma mı olduğuna bağlı olarak farklı davranmak istersiniz, sadece anlatmakla kalmaz. Bu durumda, zarif bir deyim şöyledir:

case item
  when Array
   #do something
  when Hash
   #do something else
end

.classYöntemi açmadığınızı unutmayın item.


2

Kullanabilirsiniz instance_of?

Örneğin

@some_var.instance_of?(Hash)

Bunun alt sınıflar için çalışmadığını unutmayın ! Örneğin, bir ActiveRecord::Collectionve deneyin instance_of?(Array)varsa, bu geri döner false, oysa is_a?(Array)geri döner true.
Tom Lord

0

Bir nesnenin katı olup olmadığını sınamak istiyorsanız a'yı Hashkullanın:

value = {}
value.is_a?(Hash) || value.is_a?(Array) #=> true

Ancak Ruby'nin ördek yazımına değer vermek için şöyle bir şey yapabilirsiniz:

value = {}
value.respond_to?(:[]) #=> true

value[:key]Sözdizimini kullanarak yalnızca bir değere erişmek istediğinizde kullanışlıdır .

Lütfen Array.new["key"]a TypeError.


-1
irb(main):005:0> {}.class
=> Hash
irb(main):006:0> [].class
=> Array
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.