Ответ 1
Используйте Hash values_at
метод:
from, to, name = hash.values_at(:from, :to, :name)
Это вернет nil
для любых ключей, которые не существуют в хеше.
Что такое более короткая версия?:
from = hash.fetch(:from)
to = hash.fetch(:to)
name = hash.fetch(:name)
# etc
Обратите внимание на fetch
, я хочу поднять ошибку, если ключ не существует.
Должна быть более короткая версия, например:
from, to, name = hash.fetch(:from, :to, :name) # <-- imaginary won't work
Вполне возможно использовать ActiveSupport, если это необходимо.
Используйте Hash values_at
метод:
from, to, name = hash.values_at(:from, :to, :name)
Это вернет nil
для любых ключей, которые не существуют в хеше.
Ruby 2.3 наконец вводит метод fetch_values
для хэшей, который прямо достигает этого:
{a: 1, b: 2}.fetch_values(:a, :b)
# => [1, 2]
{a: 1, b: 2}.fetch_values(:a, :c)
# => KeyError: key not found: :c
hash = {from: :foo, to: :bar, name: :buz}
[:from, :to, :name].map{|sym| hash.fetch(sym)}
# => [:foo, :bar, :buz]
[:frog, :to, :name].map{|sym| hash.fetch(sym)}
# => KeyError
my_array = {from: 'Jamaica', to: 'St. Martin'}.values_at(:from, :to, :name)
my_array.keys.any? {|key| element.nil?} && raise || my_array
Это вызовет ошибку, как вы запросили
my_array = {from: 'Jamaica', to: 'St. Martin', name: 'George'}.values_at(:from, :to, :name)
my_array.keys.any? {|key| element.nil?} && raise || my_array
Это вернет массив.
Но OP попросил провалиться по отсутствующему ключу...
class MissingKeyError < StandardError
end
my_hash = {from: 'Jamaica', to: 'St. Martin', name: 'George'}
my_array = my_hash.values_at(:from, :to, :name)
my_hash.keys.to_a == [:from, :to, :name] or raise MissingKeyError
my_hash = {from: 'Jamaica', to: 'St. Martin'}
my_array = my_hash.values_at(:from, :to, :name)
my_hash.keys.to_a == [:from, :to, :name] or raise MissingKeyError
Простейшей вещью, которую я бы хотел, было бы
from, to, name = [:from, :to, :name].map {|key| hash.fetch(key)}
В качестве альтернативы, если вы хотите использовать values_at
, вы можете использовать Hash
с блоком значений по умолчанию:
hash=Hash.new {|h, k| raise KeyError.new("key not found: #{k.inspect}") }
# ... populate hash
from, to, name = hash.values_at(:from, :to, :name) # raises KeyError on missing key
Или, если вы так склонны, обезьяна-патч Hash
class ::Hash
def fetch_all(*args)
args.map {|key| fetch(key)}
end
end
from, to, name = hash.fetch_all :from, :to, :name
Вы можете инициализировать свой хеш со значением по умолчанию для объекта KeyError
. Это вернет экземпляр KeyError, если ключ, который вы пытаетесь извлечь, отсутствует. Все, что вам нужно сделать, это проверить его класс (value) и поднять его, если его KeyError.
hash = Hash.new(KeyError.new("key not found"))
Добавьте некоторые данные в этот хэш
hash[:a], hash[:b], hash[:c] = "Foo", "Bar", nil
Наконец, просмотрите значения и поднимите ошибку, если ключ не найден.
hash.values_at(:a,:b,:c,:d).each {|v| raise v if v.class == KeyError}
Это приведет к возникновению исключения тогда и только тогда, когда ключ отсутствует. Он не будет жаловаться, если у вас есть ключ с значением nil
.