So finden Sie einen Hash-Schlüssel mit einem passenden Wert


198

Gibt es einen schnellen Ruby-Weg (ohne ein mehrzeiliges Skript schreiben zu müssen), um den Schlüssel zu erhalten, den ich mit der client_id abgleichen möchte, wenn ich den folgenden Client- Hash habe? ZB Wie bekomme ich den Schlüssel für client_id == "2180"?

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

Antworten:


176

Sie könnten Enumerable # select verwenden :

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

Beachten Sie, dass das Ergebnis ein Array aller übereinstimmenden Werte ist, wobei jedes ein Array des Schlüssels und des Werts ist.


22
@Coderama Der Unterschied zwischen findund selectbesteht darin, dass finddie erste Übereinstimmung zurückgegeben wird und select(mit einem Alias ​​versehen findAll) alle Übereinstimmungen zurückgegeben werden.
Daniel Vandersluis

Ich verstehe, also wäre dies die sicherere Option für Fälle, in denen es mehr als eine Übereinstimmung gibt.
Coderama

1
Dies ist besser, als einen ganz neuen Hash (durch Aufrufen invert) zu erstellen, nur um einen Gegenstand zu finden.
Hejazi

3
Beachten Sie, dass ab Ruby 1.9.3 ein neuer Hash mit den Übereinstimmungen zurückgegeben wird. Es wird kein Array zurückgegeben, wie es in Ruby <= 1.8.7 üblich war . clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS

Um die Schlüssel zu erhalten, setzen clients.select{|key, hash| hash["client_id"] == "2180" }.keys
Sie

407

Ruby 1.9 und höher:

hash.key(value) => key

Ruby 1.8 :

Du könntest benutzen hash.index

hsh.index(value) => key

Gibt den Schlüssel für einen bestimmten Wert zurück. Wenn nicht gefunden, wird zurückgegeben nil.

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

Um zu bekommen "orange", könnten Sie einfach verwenden:

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

2
Dies würde etwas chaotisch werden, wenn die Hashes mehrere Schlüssel hätten, da Sie den gesamten Hash geben müssten index.
Daniel Vandersluis

51
Hash#indexwird Hash#keyin Ruby 1.9
Vikrant Chaudhary

12
Beachten Sie, dass dies nur die erste Übereinstimmung zurückgibt. Wenn mehrere Hash-Paarungen mit demselben Wert vorhanden sind, wird der erste Schlüssel mit einem übereinstimmenden Wert zurückgegeben.
Mike Campbell

47

Sie können den Hash invertieren. clients.invert["client_id"=>"2180"]kehrt zurück"orange"


3
Dies scheint auch ein kluger Weg zu sein (weil es kurz ist), es zu tun!
Coderama

Dies ist, was ich für Formular-Arrays (für Auswahlfelder) benötige, die einen Rückwärts-Hash erstellen
Joseph Le Brech

22

Sie könnten hashname.key (valuename) verwenden

Oder eine Inversion kann angebracht sein. new_hash = hashname.invertgibt Ihnen eine new_hash, mit der Sie Dinge traditioneller machen können.


3
Dies ist der richtige Weg, um dies in neueren Versionen (1.9+) von Ruby zu tun.
Lars Haugseth

#invertist in diesem Fall eine wirklich schlechte Idee, da Sie im Wesentlichen Speicher für wegwerfbare Hash-Objekte zuweisen, nur um einen Schlüssel zu finden. Abhängig von der Hash-Größe hat dies schwerwiegende Auswirkungen auf die Leistung
Dr.Strangelove

15

Versuche dies:

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

4
Dies löst eine Ausnahme aus, wenn der Fund nil zurückgibt, da Sie .first nicht auf nil aufrufen können.
Schrockwell

1
Wenn Sie Rails verwenden, können Sie Ausnahmen verwenden, .try(:first)anstatt sie .firstzu vermeiden (wenn Sie erwarten, dass der Wert möglicherweise fehlt).
Aaron-Codierung

2
In können Ruby 2.3.0 +Sie den sicheren Navigator &.first am Ende des Blocks verwenden, um eine Null-Ausnahme zu verhindern
Gagan Gami


6

Aus den Dokumenten:

  • (Objekt?) Erkennen (ifnone = nil) {| obj | ...}
  • (Objekt?) Find (ifnone = nil) {| obj | ...}
  • (Objekt) erkennen (ifnone = nil)
  • (Objekt) find (ifnone = nil)

Übergibt jeden Eintrag in enum an block. Gibt den ersten zurück, für den der Block nicht falsch ist. Wenn kein Objekt übereinstimmt, ruft ifnone auf und gibt das Ergebnis zurück, wenn es angegeben wird, oder gibt andernfalls nil zurück.

Wenn kein Block angegeben ist, wird stattdessen ein Enumerator zurückgegeben.

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

Das hat bei mir funktioniert:

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

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

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


3

Der beste Weg, um den Schlüssel für einen bestimmten Wert zu finden, ist die Verwendung der Schlüsselmethode, die für einen Hash verfügbar ist.

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

Ich hoffe es löst dein Problem ...


2

Ein anderer Ansatz, den ich versuchen würde, ist die Verwendung #map

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

Dies gibt alle Vorkommen mit einem bestimmten Wert zurück. Der Unterstrich bedeutet, dass der Schlüsselwert nicht übertragen werden muss, damit er keiner Variablen zugewiesen wird. Das Array enthält Nullen, wenn die Werte nicht übereinstimmen - deshalb habe ich #compactam Ende gesetzt.


1

Hier ist eine einfache Möglichkeit, die Schlüssel eines bestimmten Werts zu finden:

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

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

... und um den Wert eines bestimmten Schlüssels zu ermitteln:

    p clients.assoc("orange") 

Sie erhalten das Schlüssel-Wert-Paar.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.