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

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.


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"})

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"


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.


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

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


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


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.


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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.