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"}
}
Coderama
sumber

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.

Daniel Vandersluis
sumber
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"})
Aillyn
sumber
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"

Peter DeWeese
sumber
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.

boulder_ruby
sumber
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
iNecas
sumber
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
12

Menurut ruby ​​doc, http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-key key (nilai) adalah metode untuk menemukan kunci pada basis nilai.

ROLE = {"customer" => 1, "designer" => 2, "admin" => 100}
ROLE.key(2)

itu akan mengembalikan "desainer".

Afzal Masood
sumber
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

Rimian
sumber
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 ...

Aditya Kapoor
sumber
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.

Jared
sumber
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.

Saleh Rastani
sumber