Come trovare una chiave hash contenente un valore corrispondente


198

Dato che ho l' hash client qui sotto , c'è un modo rapido ruby ​​(senza dover scrivere uno script multilinea) per ottenere la chiave data voglio corrispondere al client_id? Ad esempio, come ottenere la chiave per client_id == "2180"?

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

Risposte:


177

È possibile utilizzare Enumerable # select :

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

Si noti che il risultato sarà una matrice di tutti i valori corrispondenti, in cui ognuno è una matrice della chiave e del valore.


22
@Coderama La differenza tra finde selectè che findrestituisce la prima corrispondenza e select(che è aliasata da findAll) restituisce tutte le partite.
Daniel Vandersluis,

Vedo, quindi questa sarebbe l'opzione più sicura per i casi in cui esiste più di una corrispondenza.
Coderama,

1
È meglio che creare un hash completamente nuovo (chiamando invert) solo per trovare un oggetto.
Hejazi,

3
Si noti che a partire da Ruby 1.9.3 , questo restituirà un nuovo hash con le partite. Non restituirà un array, come in Ruby <= 1.8.7 . clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS,

Per ottenere le chiavi, basta inserireclients.select{|key, hash| hash["client_id"] == "2180" }.keys
Mirror318

408

Ruby 1.9 e versioni successive:

hash.key(value) => key

Ruby 1.8 :

Puoi usare hash.index

hsh.index(value) => key

Restituisce la chiave per un dato valore. Se non trovato, ritorna nil.

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

Quindi, per ottenere "orange", potresti semplicemente usare:

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

2
Questo sarebbe un po 'disordinato se gli hash avessero più chiavi, perché dovresti dare l'intero hash a index.
Daniel Vandersluis,

51
Hash#indexè stato ribattezzato Hash#keyRuby 1.9
Vikrant Chaudhary il

12
Nota che questo restituisce solo la prima corrispondenza, se ci sono più coppie di hash con lo stesso valore, restituirà la prima chiave con un valore corrispondente.
Mike Campbell,

47

Puoi invertire l'hash. clients.invert["client_id"=>"2180"]ritorna"orange"


3
Anche questo sembra un modo intelligente (perché è breve) per farlo!
Coderama,

questo è ciò di cui ho bisogno per gli array di moduli (per le caselle selezionate) che creano un hash all'indietro
Joseph Le Brech,

22

È possibile utilizzare hashname.key (nome-valore)

Oppure, un'inversione può essere in ordine. new_hash = hashname.invertti darà un new_hashche ti consente di fare le cose in modo più tradizionale.


3
Questo è il modo corretto di farlo nelle ultime versioni (1.9+) di Ruby.
Lars Haugseth,

#invertè una pessima idea in questo caso, dal momento che si sta essenzialmente allocando memoria per l'oggetto hash buttato via solo per il gusto di trovare una chiave. A seconda della dimensione dell'hash, ha un grave impatto sulle prestazioni
Dr.Strangelove,

15

prova questo:

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

4
Ciò genererà un'eccezione se la ricerca restituisce zero, poiché non è possibile chiamare prima il nil.
Schrockwell,

1
Se si utilizza Rails è possibile utilizzare .try(:first)invece di .firstevitare eccezioni (se si prevede che sia possibile che manchi il valore).
codifica in aaron il

2
in Ruby 2.3.0 +è possibile utilizzare il navigatore di sicurezza &.first alla fine del blocco per evitare Nil Exception
Gagan Gami


6

Dai documenti:

  • (Oggetto?) Rileva (ifnone = nil) {| obj | ...}
  • (Object?) Find (ifnone = nil) {| obj | ...}
  • (Object) rileva (ifnone = nil)
  • (Object) find (ifnone = nil)

Passa ogni voce in enum per bloccare. Restituisce il primo per il quale il blocco non è falso. Se nessun oggetto corrisponde, chiama ifnone e restituisce il risultato quando viene specificato, oppure restituisce zero altrimenti.

Se non viene fornito alcun blocco, viene invece restituito un enumeratore.

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

Questo ha funzionato per me:

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

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

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


3

Il modo migliore per trovare la chiave per un determinato valore è utilizzare il metodo chiave disponibile per un hash ....

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

Spero che risolva il tuo problema ...


2

Un altro approccio che vorrei provare è utilizzando #map

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

Ciò restituirà tutte le occorrenze di un determinato valore. Il carattere di sottolineatura significa che non abbiamo bisogno del valore della chiave per essere trasportato in modo tale che non venga assegnato a una variabile. L'array conterrà zero se i valori non corrispondono - ecco perché l'ho messo #compactalla fine.


1

Ecco un modo semplice per trovare le chiavi di un dato valore:

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

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

... e per trovare il valore di una determinata chiave:

    p clients.assoc("orange") 

ti darà la coppia chiave-valore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.