Comment trouver une clé de hachage contenant une valeur correspondante

198

Étant donné que j'ai le hachage des clients ci-dessous , y a-t-il un moyen rapide (sans avoir à écrire un script multi-lignes) pour obtenir la clé étant donné que je veux faire correspondre le client_id? Par exemple, comment obtenir la clé client_id == "2180"?

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

Réponses:

177

Vous pouvez utiliser Enumerable # select :

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

Notez que le résultat sera un tableau de toutes les valeurs correspondantes, où chacun est un tableau de la clé et de la valeur.

Daniel Vandersluis
la source
22
@Coderama La différence entre findet selectest que findrenvoie la première correspondance et select(qui est aliasée par findAll) renvoie toutes les correspondances.
Daniel Vandersluis
Je vois, donc ce serait l'option la plus sûre pour les cas où il y a plus d'une correspondance.
Coderama
1
C'est mieux que de créer un tout nouveau hachage (en appelant invert) juste pour trouver un élément.
Hejazi
3
Notez qu'à partir de Ruby 1.9.3 , cela retournera un nouveau hachage avec les correspondances. Il ne retournera pas de tableau, comme c'était le cas auparavant dans Ruby <= 1.8.7 . clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS
Pour obtenir la ou les clés, il suffit de mettreclients.select{|key, hash| hash["client_id"] == "2180" }.keys
Mirror318
408

Ruby 1.9 et supérieur:

hash.key(value) => key

Rubis 1.8 :

Vous pourriez utiliser hash.index

hsh.index(value) => key

Renvoie la clé pour une valeur donnée. S'il n'est pas trouvé, retourne nil.

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

Donc, pour obtenir "orange", vous pouvez simplement utiliser:

clients.key({"client_id" => "2180"})
Aillyn
la source
2
Cela deviendrait un peu compliqué si les hachages avaient plusieurs clés, car vous auriez besoin de donner tout le hachage index.
Daniel Vandersluis
51
Hash#indexest renommé Hash#keyen Ruby 1.9
Vikrant Chaudhary
12
Notez que cela ne renvoie que la première correspondance, s'il existe plusieurs paires de hachage avec la même valeur, il retournera la première clé avec une valeur correspondante.
Mike Campbell du
47

Vous pouvez inverser le hachage. clients.invert["client_id"=>"2180"]Retour"orange"

Peter DeWeese
la source
3
Cela semble aussi être un moyen intelligent (car c'est court) de le faire!
Coderama
c'est ce dont j'ai besoin pour les tableaux de formulaires (pour les cases sélectionnées) qui créent un hachage vers l'arrière
Joseph Le Brech
22

Vous pouvez utiliser hashname.key (nom de valeur)

Ou, une inversion peut être en ordre. new_hash = hashname.invertvous donnera un new_hashqui vous permet de faire les choses de façon plus traditionnelle.

boulder_ruby
la source
3
C'est la bonne façon de le faire dans les versions récentes (1.9+) de Ruby.
Lars Haugseth
#invertest une très mauvaise idée dans ce cas, car vous allouez essentiellement de la mémoire pour un objet de hachage à jeter juste pour trouver une clé. Selon la taille du hachage, cela a un impact sérieux sur les performances
Dr.Strangelove
15

essaye ça:

clients.find{|key,value| value["client_id"] == "2178"}.first
iNecas
la source
4
Cela lèvera une exception si la recherche renvoie nil, car vous ne pouvez pas appeler .first sur nil.
Schrockwell
1
Si vous utilisez Rails, vous pouvez utiliser .try(:first)au lieu de .firstpour éviter les exceptions (si vous vous attendez à ce que la valeur soit manquante).
aaron-coding
2
en Ruby 2.3.0 +vous pouvez utiliser le navigateur en toute sécurité &.first à la fin du bloc pour empêcher de Nil Exception
Gagan Gami
6

De la documentation:

  • (Objet?) Détecter (ifnone = nil) {| obj | ...}
  • (Objet?) Find (ifnone = nil) {| obj | ...}
  • (Objet) détecter (ifnone = nil)
  • (Object) find (ifnone = nil)

Passe chaque entrée enum à bloquer. Renvoie le premier pour lequel le bloc n'est pas faux. Si aucun objet ne correspond, appelle ifnone et renvoie son résultat lorsqu'il est spécifié, ou renvoie nil sinon.

Si aucun bloc n'est donné, un énumérateur est renvoyé à la place.

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

Cela a fonctionné pour moi:

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

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

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

Rimian
la source
3

La meilleure façon de trouver la clé pour une valeur particulière est d'utiliser la méthode de clé disponible pour un hachage ....

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

J'espère que cela résout votre problème ...

Aditya Kapoor
la source
2

Une autre approche que j'essaierais serait d'utiliser #map

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

Cela renverra toutes les occurrences de valeur donnée. Le trait de soulignement signifie que nous n'avons pas besoin que la valeur de la clé soit transportée pour qu'elle ne soit pas affectée à une variable. Le tableau contiendra nils si les valeurs ne correspondent pas - c'est pourquoi je mets #compactà la fin.

Jared
la source
1

Voici un moyen simple de trouver les clés d'une valeur donnée:

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

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

... et pour trouver la valeur d'une clé donnée:

    p clients.assoc("orange") 

il vous donnera la paire clé-valeur.

Saleh Rastani
la source