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

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.

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

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

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

Laut Ruby Doc http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-key Schlüssel (Wert) ist die Methode, um den Schlüssel auf der Basis des Wertes zu finden.

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

es wird den "Designer" zurückgeben.

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

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

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

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

Saleh Rastani
quelle