Jak znaleźć klucz skrótu zawierający pasującą wartość


198

Biorąc pod uwagę, że mam poniższy skrót klientów , czy istnieje szybki rubinowy sposób (bez konieczności pisania skryptu składającego się z wielu wierszy), aby uzyskać klucz, biorąc pod uwagę, że chcę dopasować identyfikator klienta? Np. Jak zdobyć klucz client_id == "2180"?

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

Odpowiedzi:


176

Możesz użyć Enumerable # select :

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

Zauważ, że wynikiem będzie tablica wszystkich pasujących wartości, gdzie każda jest tablicą klucza i wartości.


22
@Coderama Różnica między findi selectpolega na tym, że findzwraca pierwsze dopasowanie, a select(które jest aliasowane findAll) zwraca wszystkie dopasowania.
— Daniel Vandersluis,

Rozumiem, więc byłaby to bezpieczniejsza opcja dla przypadków, w których występuje więcej niż jedno dopasowanie.
— Coderama,

1
Jest to lepsze niż tworzenie całego nowego skrótu (przez dzwonienie invert) tylko w celu znalezienia elementu.
— Hejazi

3
Zauważ, że od Ruby 1.9.3 , to zwróci nowy skrót z dopasowaniami. Nie zwróci tablicy, jak kiedyś w Ruby <= 1.8.7 . clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
— AndrewS,

Aby uzyskać klucz (klucze), po prostu włóżclients.select{|key, hash| hash["client_id"] == "2180" }.keys
— Mirror318

407

Ruby 1.9 i nowszy:

hash.key(value) => key

Ruby 1.8 :

Możesz użyć hash.index

hsh.index(value) => key

Zwraca klucz dla danej wartości. Jeśli nie znaleziono, zwraca nil.

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

Aby uzyskać "orange", możesz po prostu użyć:

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

2
Byłoby to trochę niechlujne, gdyby skróty miały wiele kluczy, ponieważ musiałbyś oddać cały skrót index.
— Daniel Vandersluis,

51
Hash#indexprzemianowano na Hash#keyRuby 1.9
— Vikrant Chaudhary

12
Zauważ, że to zwraca tylko pierwsze dopasowanie, jeśli istnieje wiele par skrótów o tej samej wartości, zwróci pierwszy klucz z pasującą wartością.
— Mike Campbell

47

Możesz odwrócić skrót. clients.invert["client_id"=>"2180"]zwroty"orange"


3
Wydaje się to również sprytnym sposobem (ponieważ jest krótki), aby to zrobić!
— Coderama,

tego właśnie potrzebuję dla tablic formularzy (dla wybranych pól), które tworzą hash wsteczny
— Joseph Le Brech

22

Możesz użyć hashname.key (nazwa wartości)

Lub odwrócenie może być w porządku. new_hash = hashname.invertda ci coś, new_hashco pozwala robić rzeczy bardziej tradycyjnie.


3
Jest to właściwy sposób, aby to zrobić w najnowszych wersjach Ruby (1.9+).
— Lars Haugseth,

#invertjest naprawdę złym pomysłem w tym przypadku, ponieważ w zasadzie alokujesz pamięć dla wyrzucanego obiektu mieszającego tylko ze względu na znalezienie klucza. W zależności od wielkości skrótu ma to poważny wpływ na wydajność
— Dr.Strangelove

15

Spróbuj tego:

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

4
Spowoduje to zgłoszenie wyjątku, jeśli find zwróci zero, ponieważ nie można wywołać .first na zero.
— Schrockwell,

1
Jeśli używasz Railsów, możesz użyć .try(:first)zamiast .firstunikać wyjątków (jeśli spodziewasz się, że będzie możliwe, że brakuje wartości).
— kodowanie aaron

2
w Ruby 2.3.0 +możesz użyć bezpiecznego nawigatora &.first na końcu bloku, aby zapobiec zerowemu wyjątkowi
— Gagan Gami,


6

Z dokumentów:

  • (Obiekt?) Wykryj (ifnone = zero) {| obj | ...}
  • (Obiekt?) Znajdź (ifnone = zero) {| obj | ...}
  • Wykrywanie (obiektu) (ifnone = zero)
  • (Obiekt) znajdź (ifnone = zero)

Przechodzi każdy wpis w enum do zablokowania. Zwraca pierwszy, dla którego blok nie jest fałszywy. Jeśli żaden obiekt nie pasuje, wywołuje ifnone i zwraca wynik, gdy jest określony, lub zwraca zero w przeciwnym razie.

Jeśli nie podano żadnego bloku, zamiast tego zwracany jest moduł wyliczający.

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

To działało dla mnie:

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

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

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


3

Najlepszym sposobem znalezienia klucza dla określonej wartości jest użycie metody klucza dostępnej dla skrótu ....

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

Mam nadzieję, że to rozwiąże twój problem ...


2

Innym podejściem, którego spróbowałbym, jest użycie #map

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

Zwróci to wszystkie wystąpienia o podanej wartości. Podkreślenie oznacza, że ​​nie potrzebujemy przenosić wartości klucza, aby w ten sposób nie był przypisany do zmiennej. Tablica będzie zawierać zero, jeśli wartości się nie zgadzają - dlatego umieszczam #compactna końcu.


1

Oto prosty sposób na znalezienie kluczy o danej wartości:

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

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

... i znaleźć wartość danego klucza:

    p clients.assoc("orange") 

da ci parę klucz-wartość.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.