Eşleşen bir değer içeren bir karma anahtarı bulma


198

Istemci hash var verilen göz önüne alındığında , client_id maç istiyorum istiyorum verilen anahtarı elde etmek için (çok satırlı bir komut dosyası yazmak zorunda kalmadan) hızlı bir yakut yolu var mı? Örneğin, anahtar nasıl alınır client_id == "2180"?

clients = {
  "yellow"=>{"client_id"=>"2178"}, 
  "orange"=>{"client_id"=>"2180"}, 
  "red"=>{"client_id"=>"2179"}, 
  "blue"=>{"client_id"=>"2181"}
}

Yanıtlar:


177

Enumerable # select komutunu kullanabilirsiniz :

clients.select{|key, hash| hash["client_id"] == "2180" }
#=> [["orange", {"client_id"=>"2180"}]]

Sonucun her biri anahtar ve değerin bir dizisi olduğu eşleşen tüm değerlerin bir dizisi olacağını unutmayın.


22
Arasındaki fark @Coderama findve selectolmasıdır finddöner birinci eşleşme ve select(göre ad olarak findAll) tüm maçları döndürür.
Daniel Vandersluis

Görüyorum ki, bu birden fazla eşleşmenin olduğu durumlarda daha güvenli bir seçenek olurdu.
Coderama

1
Bu, invertsadece bir öğe bulmak için yepyeni bir karma (çağrı yaparak ) oluşturmaktan daha iyidir .
Hejazi

3
İtibariyle unutmayın Ruby 1.9.3 , bu maçları ile yeni bir karma dönecektir. Ruby <= 1.8.7'de olduğu gibi bir dizi döndürmez . clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS

Anahtarları almak için basitçe şunu koyclients.select{|key, hash| hash["client_id"] == "2180" }.keys
Mirror318

408

Yakut 1.9 ve üstü:

hash.key(value) => key

Yakut 1.8 :

Kullanabilirsin hash.index

hsh.index(value) => key

Belirli bir değerin anahtarını döndürür. Bulunamazsa geri döner nil.

h = { "a" => 100, "b" => 200 }
h.index(200) #=> "b"
h.index(999) #=> nil

Yani almak için "orange", sadece kullanabilirsiniz:

clients.key({"client_id" => "2180"})

2
Karmaların birden fazla anahtarı olsaydı bu biraz karışık olurdu, çünkü tüm karma değerini vermeniz gerekir index.
Daniel Vandersluis

51
Hash#indexadını Hash#keyRuby 1.9 olarak değiştirdi
Vikrant Chaudhary

12
Bunun yalnızca ilk eşleşmeyi döndürdüğünü, aynı değere sahip birden çok karma eşlemesi varsa, eşleşen bir değere sahip ilk anahtarı döndüreceğini unutmayın.
Mike Campbell

47

Karmayı tersine çevirebilirsiniz. clients.invert["client_id"=>"2180"]İadeler"orange"


3
Bu da bunu yapmak için akıllıca bir yol gibi görünüyor (çünkü kısa)!
Coderama

Bu geriye doğru bir karma oluşturmak form dizileri (belirli kutular için) için ihtiyacım olan
Joseph Le Brech

22

Hashname.key (değer adı) kullanabilirsiniz

Ya da bir tersine dönme sırası olabilir. size işleri geleneksel olarak yapmanıza izin new_hash = hashname.invertveren bir ürün verecektir new_hash.


3
Ruby'nin son sürümlerinde (1.9+) bunu yapmanın doğru yolu budur.
Lars Haugseth

#invertbu durumda gerçekten kötü bir fikir, çünkü aslında sadece bir anahtar bulmak uğruna atmak için hash nesnesi için bellek ayırıyorsunuz. Karma boyutuna bağlı olarak, ciddi performans etkisi vardır
Dr.Strangelove

15

bunu dene:

clients.find{|key,value| value["client_id"] == "2178"}.first

4
Bulma nil döndürürse bu bir istisna atar, çünkü nil'de .first çağıramazsınız.
Schrockwell

1
Rails kullanıyorsanız .try(:first), .firstistisnaları önlemek için kullanabilirsiniz (değerin eksik olmasını bekliyorsanız).
aaron-kodlama

2
içinde Ruby 2.3.0 +kullanabileceğiniz güvenli navigasyoncumuzu &.first Nil Exception kaynağından önlemek için blok sonunda
Gagan GAMİ


6

Dokümanlardan:

  • (Nesne?) Algıla (ifnone = nil) {| obj | ...}
  • (Nesne?) Bul (ifnone = nil) {| obj | ...}
  • (Nesne) algılama (ifnone = nil)
  • (Nesne) bulma (ifnone = nil)

Enum'daki her girdiyi engellenecek şekilde geçirir. Bloğun yanlış olmadığı ilk satırı döndürür. Hiçbir nesne eşleşmezse, ifnone öğesini çağırır ve belirtildiğinde sonucunu döndürür veya aksi halde nil değerini döndürür.

Herhangi bir blok verilmezse, bunun yerine bir numaralandırıcı döndürülür.

(1..10).detect  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
(1..100).detect {|i| i % 5 == 0 and i % 7 == 0 }   #=> 35

Bu benim için çalıştı:

clients.detect{|client| client.last['client_id'] == '2180' } #=> ["orange", {"client_id"=>"2180"}] 

clients.detect{|client| client.last['client_id'] == '999999' } #=> nil 

Bkz. Http://rubydoc.info/stdlib/core/1.9.2/Enumerable#find-instance_method


3

Belirli bir değer için anahtar bulmak için en iyi yolu bir karma için kullanılabilir anahtar yöntemini kullanmaktır ....

gender = {"MALE" => 1, "FEMALE" => 2}
gender.key(1) #=> MALE

Umarım sorununuzu çözer ...


2

Deneyeceğim başka bir yaklaşım #map

clients.map{ |key, _| key if clients[key] == {"client_id"=>"2180"} }.compact 
#=> ["orange"]

Bu, verilen değerin tüm oluşumlarını döndürür. Alt çizgi, anahtarın değerinin taşınması gerekmediği anlamına gelir, böylece bir değişkene atanmaz. Değerler eşleşmezse dizi nils içerecektir - bu yüzden #compactsonuna koyuyorum .


1

Heres, verilen bir değerin anahtarlarını bulmanın kolay bir yoludur:

    clients = {
      "yellow"=>{"client_id"=>"2178"}, 
      "orange"=>{"client_id"=>"2180"}, 
      "red"=>{"client_id"=>"2179"}, 
      "blue"=>{"client_id"=>"2181"}
    }

    p clients.rassoc("client_id"=>"2180")

... ve verilen bir anahtarın değerini bulmak için:

    p clients.assoc("orange") 

size anahtar / değer çiftini verecektir.

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.