Як знайти хеш-ключ, що містить відповідне значення


198

Враховуючи, що у мене є хеш клієнтів нижче , чи є швидкий спосіб рубіну (без необхідності писати багаторядковий скрипт), щоб отримати ключ, заданий я хочу відповідати client_id? Наприклад, як отримати ключ client_id == "2180"?

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

Відповіді:


176

Ви можете використовувати численні # вибір :

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

Зауважте, що результатом буде масив усіх відповідних значень, де кожне - це масив ключа та значення.


22
@Coderama Різниця між findі selectполягає в тому, що findповертає першу відповідність і select(яка відчужена findAll) повертає всі збіги.
Даніель Вандерслуйс

Я бачу, тому це був би більш безпечний варіант для випадків, коли більше одного матчу.
Coderama

1
Це краще, ніж створити цілком новий хеш (зателефонувавши invert), просто знайти предмет.
Хеджазі

3
Зауважте, що станом на Ruby 1.9.3 це поверне новий хеш із сірниками. Він не поверне масив, як це було раніше в Ruby <= 1.8.7 . clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS

Щоб отримати ключі, просто покладітьclients.select{|key, hash| hash["client_id"] == "2180" }.keys
Mirror318

407

Ruby 1.9 і більше:

hash.key(value) => key

Рубін 1,8 :

Ви можете використовувати hash.index

hsh.index(value) => key

Повертає ключ для заданого значення. Якщо не знайдено, повертається nil.

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

Отже, щоб отримати "orange", ви можете просто скористатися:

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

2
Це вийшло б безладним, якби у хешах було кілька клавіш, тому що вам потрібно було б надати весь хеш index.
Даніель Вандерслуйс,

51
Hash#indexперейменовано на Hash#keyRuby 1.9
Vikrant Chaudhary

12
Зауважте, що це повертає лише перший збіг, якщо є кілька пар хешів з однаковим значенням, він поверне перший ключ зі значенням відповідності.
Майк Кемпбелл

47

Ви можете перевернути хеш. clients.invert["client_id"=>"2180"]повертає"orange"


3
Це також здається розумним способом (бо це коротко) зробити це!
Coderama

це те, що мені потрібно для масивів форм (для вибраних полів), які створюють хеш-зворотній бік
Джозеф Ле Брех

22

Ви можете використовувати hashname.key (valuename)

Або інверсія може бути в порядку. new_hash = hashname.invertдасть вам new_hashте, що дозволяє робити речі більш традиційно.


3
Це правильний спосіб зробити це в останніх версіях (1.9+) Ruby.
Lars Haugseth

#invertв цьому випадку дійсно погана ідея, оскільки ви по суті виділяєте пам’ять на викинутий хеш-об’єкт лише заради пошуку ключа. Залежно від розміру хешу, це може мати серйозний вплив на продуктивність
Dr.Strangelove

15

спробуйте це:

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

4
Це викине виняток, якщо знахідка поверне нуль, тому що ви не можете зателефонувати.
Шроквелл

1
Якщо ви використовуєте Rails, ви можете використовувати .try(:first)замість того, .firstщоб уникнути винятків (Якщо ви очікуєте, що це значення може бути відсутнім).
кодування

2
в Ruby 2.3.0 +ви можете використовувати безпечний навігатор &.first в кінці блоку , щоб запобігти від Nil Виняток
Gagan гами


6

З документів:

  • (Об'єкт?) Виявити (ifnone = нуль) {| obj | ...}
  • (Об'єкт?) Знайти (ifnone = нуль) {| obj | ...}
  • (Об'єкт) виявити (ifnone = нуль)
  • (Об’єкт) знайти (ifnone = нуль)

Проходить кожен запис у перерахунку до блоку. Повертає перший, для якого блок не хибний. Якщо жоден об'єкт не відповідає, викликає ifnone і повертає його результат, коли він вказаний, або повертає нуль інакше.

Якщо блок не вказаний, замість нього повертається нумератор.

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

Це працювало для мене:

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

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

Дивіться: http://rubydoc.info/stdlib/core/1.9.2/Eumerable#find-instance_method


3

Найкращий спосіб знайти ключ для певного значення - скористатися методом ключа, який доступний для хешу ....

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

Я сподіваюся, що це вирішить вашу проблему ...


2

Ще один підхід, який я б спробував, - це використання #map

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

Це поверне всі випадки заданого значення. Підкреслення означає, що нам не потрібно переносити значення ключа, щоб його не присвоїли змінній. Масив буде містити нулі, якщо значення не збігаються - тому я ставлю #compactв кінці.


1

Ось простий спосіб знайти ключі заданого значення:

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

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

... і знайти значення заданого ключа:

    p clients.assoc("orange") 

це дасть вам пару ключ-значення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.