2013-10-01 4 views
6

У меня есть следующий хэш:Как использовать метод выборки для вложенного хэша?

hash = {'name' => { 'Mike' => { 'age' => 10, 'gender' => 'm' } } } 

я могу получить доступ к возрасту по:

hash['name']['Mike']['age'] 

Что делать, если я использовал Hash#fetch метод? Как получить ключ из вложенного хэша?

Как упоминалось Серхио, как это сделать (без создания чего-то для себя) было бы цепочкой fetch методов:

hash.fetch('name').fetch('Mike').fetch('age') 
+1

'выборки ('имя') выборки ('Mike')', нет? –

+0

@SergioTulentsev Я знаю, но я думал, если есть что-то более тонкое, чем прикованные методы извлечения – PericlesTheo

+0

Вы всегда можете написать свой собственный сахар для этого :) –

ответ

2

Там нет встроенного метода, который я знаю. У меня это в моем текущем проекте

class Hash 
    def fetch_path(*parts) 
    parts.reduce(self) do |memo, key| 
     memo[key.to_s] if memo 
    end 
    end 
end 

# usage 
hash.fetch_path('name', 'Mike', 'age') 

Вы можете легко изменить его, чтобы использовать #fetch вместо #[] (если вы так хотите).

0

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

hash = Hash.new { |h1, k1| h1[k1] = Hash.new { |h2, k2| h2[k2] = Hash.new { |h3, k3| } } } 
hash['name']['Mike'] 
# {} 
hash['name']['Steve']['age'] = 20 
hash 
# {"name"=>{"Mike"=>{}, "Steve"=>{"age"=>20}}} 

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

+0

Эй, спасибо за анонимный downvote через год после факта. Как насчет комментария? – Max

-3

если вы можете

использование:

hash[["ayy","bee"]] 

вместо:

hash["ayy"]["bee"] 

это будет сэкономить много раздражений

19

От Руби 2.3.0 вперед, вы могут использовать Hash#dig:

hash.dig('name', 'Mike', 'age') 

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

Вы можете использовать драгоценный камень ruby_dig, пока не перейдете.

+2

То есть _really_ не бонус. –

+0

@ DuncanBayne в динамически типизированных языках, где использование «nil» в качестве значения фальшивки - это идиома - это так. Рассмотрим альтернативу старых рельсов, которая заключается в цепочке 'try' invocations - она ​​будет делать то же самое. – ndn

+0

Я верю, что правильной альтернативой является цепочка 'fetch' invocations, которая вызывает ошибку по умолчанию, если ключ не найден. Затем можно тщательно, сознательно предоставлять значения по умолчанию по мере необходимости. Я видел много ошибок, вызванных кодом - и Ruby и Coffeescript - беспечно рассматривая пропущенные значения как ноль. –

0

Как Руби 2.3.0:

Вы также можете использовать &. называется "безопасной навигации оператора" как: hash&.[]('name')&.[]('Mike')&.[]('age'). Это абсолютно безопасно.

Использование является не безопасно, как hash.dig(:name, :Mike, :age) потерпит неудачу, если hash равна нулю.

Однако вы можете комбинировать их как: hash&.dig(:name, :Mike, :age).

Так одно из следующих действий является безопасным для использования:.

hash&.[]('name')&.[]('Mike')&.[]('age')

hash&.dig(:name, :Mike, :age)

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