Cara menemukan kunci hash yang berisi nilai yang cocok


198

Mengingat saya memiliki hash klien di bawah ini , apakah ada cara ruby ​​cepat (tanpa harus menulis skrip multi-line) untuk mendapatkan kunci mengingat saya ingin mencocokkan client_id? Misalnya, Bagaimana cara mendapatkan kunci client_id == "2180"?

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

Jawaban:


176

Anda dapat menggunakan Enumerable # select :

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

Perhatikan bahwa hasilnya akan menjadi array dari semua nilai yang cocok, di mana masing-masing adalah array dari kunci dan nilai.


22
@Coderama Perbedaan antara finddan selectadalah yang findmengembalikan kecocokan pertama dan select(yang disebut dengan findAll) mengembalikan semua kecocokan.
Daniel Vandersluis

Begitu ya, jadi ini akan menjadi opsi yang lebih aman untuk contoh di mana ada lebih dari satu pertandingan.
Coderama

1
Ini lebih baik daripada membuat hash baru (dengan menelepon invert) hanya untuk menemukan item.
Hejazi

3
Perhatikan bahwa pada Ruby 1.9.3 , ini akan mengembalikan hash baru dengan pertandingan. Itu tidak akan mengembalikan array, seperti dulu di Ruby <= 1.8.7 . clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS

Untuk mendapatkan kunci, cukup cantumkanclients.select{|key, hash| hash["client_id"] == "2180" }.keys
Mirror318

407

Ruby 1.9 dan lebih tinggi:

hash.key(value) => key

Ruby 1.8 :

Anda bisa menggunakannya hash.index

hsh.index(value) => key

Mengembalikan kunci untuk nilai yang diberikan. Jika tidak ditemukan, kembali nil.

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

Jadi untuk mendapatkan "orange", Anda bisa menggunakan:

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

2
Ini akan menjadi berantakan jika hash memiliki beberapa kunci, karena Anda harus memberikan seluruh hash index.
Daniel Vandersluis

51
Hash#indexberganti nama menjadi Hash#keydi Ruby 1.9
Vikrant Chaudhary

12
Perhatikan bahwa ini hanya mengembalikan kecocokan pertama, jika ada beberapa pasangan hash dengan nilai yang sama, itu akan mengembalikan kunci pertama dengan nilai yang cocok.
Mike Campbell

47

Anda dapat membalikkan hash. clients.invert["client_id"=>"2180"]kembali"orange"


3
Ini juga sepertinya cara yang pintar (karena pendek) untuk melakukannya!
Coderama

inilah yang saya butuhkan untuk form array (untuk kotak-kotak pilihan) yang membuat hash mundur
Joseph Le Brech

22

Anda dapat menggunakan hashname.key (valuename)

Atau, inversi mungkin berurutan. new_hash = hashname.invertakan memberi Anda new_hashyang memungkinkan Anda melakukan hal-hal yang lebih tradisional.


3
Ini adalah cara yang tepat untuk melakukannya di Ruby versi terbaru (1.9+).
Lars Haugseth

#invertadalah ide yang sangat buruk dalam hal ini, karena Anda pada dasarnya mengalokasikan memori untuk objek hash yang dibuang hanya demi menemukan kunci. Tergantung pada ukuran hash itu memiliki dampak kinerja yang serius
Dr.Strangelove

15

coba ini:

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

4
Ini akan memunculkan pengecualian jika menemukan mengembalikan nihil, karena Anda tidak dapat memanggil .fir pertama pada nihil.
Schrockwell

1
Jika menggunakan Rails, Anda dapat menggunakan .try(:first)alih-alih .firstmenghindari pengecualian (Jika Anda mengharapkannya mungkin nilai tidak ada).
Aaron-coding

2
di Ruby 2.3.0 +Anda dapat menggunakan navigator aman &.first di ujung blok untuk mencegah dari Nil Exception
Gagan Gami


6

Dari dokumen:

  • (Object?) Mendeteksi (ifnone = nil) {| obj | ...}
  • (Object?) Find (ifnone = nil) {| obj | ...}
  • (Objek) deteksi (ifnone = nil)
  • (Objek) find (ifnone = nil)

Lewati setiap entri di enum untuk diblokir. Mengembalikan blok pertama yang tidak salah. Jika tidak ada objek yang cocok, panggil ifnone dan kembalikan hasilnya saat ditentukan, atau kembalikan nihil sebaliknya.

Jika tidak ada blok yang diberikan, enumerator malah dikembalikan.

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

Ini bekerja untuk saya:

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

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

Lihat: http://rubydoc.info/stdlib/core/1.9.2/Enumerable#find-instance_method


3

Cara terbaik untuk menemukan kunci untuk nilai tertentu adalah dengan menggunakan metode kunci yang tersedia untuk ...

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

Saya harap ini memecahkan masalah Anda ...


2

Pendekatan lain yang akan saya coba adalah dengan menggunakan #map

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

Ini akan mengembalikan semua kejadian dari nilai yang diberikan. Garis bawah berarti bahwa kita tidak perlu nilai kunci untuk dibawa-bawa sehingga tidak ditugaskan ke variabel. Array akan berisi nils jika nilainya tidak cocok - itu sebabnya saya letakkan #compactdi akhir.


1

Inilah cara mudah untuk menemukan kunci dari nilai yang diberikan:

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

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

... dan untuk menemukan nilai kunci yang diberikan:

    p clients.assoc("orange") 

itu akan memberi Anda pasangan nilai kunci.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.