2010-09-25 2 views
153

Учитывая, что у меня есть ниже клиентов hash, есть ли быстрый рубиновый путь (без необходимости писать многострочный скрипт), чтобы получить заданный ключ. Я хочу совместить ID клиента? Например. Как получить ключ для client_id == "2180"?Как найти хэш-ключ, содержащий подходящее значение

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

ответ

144

Вы можете использовать Enumerable#select:

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

Обратите внимание, что результат будет массив всех значений соответствия, где каждый представляет собой массив из ключа и значения.

+0

Это тоже работает! – Coderama

+18

@Coderama. Разница между 'find' и' select' заключается в том, что 'find' возвращает первое совпадение, а' select' (который является псевдонимом 'findAll') возвращает все совпадения. –

+0

Я вижу, так что это будет более безопасный вариант для случаев, когда есть более одного совпадения. – Coderama

9

попробовать это:

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

Это сработало отлично – Coderama

+4

Это вызовет исключение, если find вернет нуль, потому что вы не можете вызвать .first на nil. – Schrockwell

+1

Если вы используете Rails, вы можете использовать '.try (: first)' вместо '.first', чтобы избежать исключений (если вы ожидаете, что это возможно для отсутствия значения). –

323

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

Я получаю нуль, когда я запускаю это ... – Coderama

+0

@Coderama Я не http://codepad.org/2JpX9ei5 – Aillyn

+2

Это было бы грязно, если бы хеши имели несколько ключей, потому что вам нужно было бы дать весь хэш для индекса. –

46

Вы можете инвертировать хэш. clients.invert["client_id"=>"2180"] возвращает "orange"

+3

Это тоже кажется умным способом (потому что это коротко), чтобы сделать это! – Coderama

+0

Это то, что мне нужно для массивов форм (для отдельных блоков), которые создают обратный хэш. –

21

Вы можете использовать hashname.key (VALUENAME)

Или, инверсия может быть в порядке. new_hash = hashname.invert предоставит вам new_hash, который позволит вам делать что-то более традиционно.

+3

Это правильный способ сделать это в последних версиях (1.9+) Ruby. –

+0

'# invert' - действительно плохая идея в этом случае, поскольку вы по существу выделяете память для хеш-объекта throw-away только ради поиска ключа. В зависимости от размера хеша он имеет серьезное влияние на производительность –

3

Из документов:

  • (? Object) обнаружения (ifnone = ноль) {| OBJ | ...}
  • (Object?) Find (ifnone = nil) {| 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/Enumerable#find-instance_method

0

Лучший способом найти ключ для конкретного значения является использование ключа метода, который доступен для хэша. ...

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

Надеюсь, он решает вашу проблему ...

10

В соответствии с ruby ​​doc http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-key ключ (значение) - это метод поиска ключа на основе значения.

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

он вернет «конструктор».

1

Другой подход, который я хотел бы попробовать это с помощью #map

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

Это вернет всех вхождений заданного значения. Подчеркивание означает, что нам не нужно использовать значение ключа, чтобы оно не было привязано к переменной. Массив будет содержать nils, если значения не совпадают - вот почему я положил #compact в конец.

0

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

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

это даст вам ключ-значение.

Смежные вопросы