Подтвердить что ты не робот

Как получить сразу несколько значений хэша?

Что такое более короткая версия?:

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, если это необходимо.

4b9b3361

Ответ 1

Используйте Hash values_at метод:

from, to, name = hash.values_at(:from, :to, :name)

Это вернет nil для любых ключей, которые не существуют в хеше.

Ответ 2

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

Ответ 3

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

Ответ 4

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

Ответ 5

Простейшей вещью, которую я бы хотел, было бы

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

Ответ 6

Вы можете инициализировать свой хеш со значением по умолчанию для объекта 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.