2013-07-15 1 views
41

Что более короткая версия этого ?:Как получить сразу несколько значений хэша?

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 при необходимости. values_at метод

+0

Одним из важных и молчаливый вопрос есть. Зачем вы хотите переназначить значения из хэша в vars? –

+0

@MichaelSzyndel Я не могу разобрать ваш комментарий выше. – sawa

+1

Почему вы хотите делать 'from = hash.fetch (: from); to = hash.fetch (: to); '... вместо использования' hash [: from] '? –

ответ

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 
71

Используйте хэш-функции по:

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

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

+4

Это не удовлетворяет требованиям OP. – sawa

+0

@MichaelSzyndel. Читайте этот вопрос самостоятельно. – sawa

+0

Не существует такого метода, который будет извлекать несколько ключей и исключений для исключений. Одна из причин может заключаться в том, что когда возникает исключение - когда ключ несуществующий (он может оставить неназначенные переменные для других ключей) или после выбора всех ключей? Легко добавить такую ​​проверку самостоятельно, и я не могу понять, почему вы настаиваете на том, чтобы поднимать исключение. –

2
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 
+1

'my_array.any? {| Элемент | element.nil?} && raise' будет некорректным, потому что ключ может существовать с значением «nil». –

+0

Вы правы. Я проверил значение, а не ключ. Я буду редактировать ключ. – vgoff

+0

'keys.to_a == [: from,: to,: name]' неверно. Здесь порядок будет иметь значение, но ключи Хэша не имеют особого порядка, он должен быть как минимум 'keys.to_a - [: from,: to,: name] == []'. В целом, это просто больше усилий, чем того стоит. –

1

Самое простое, что я хотел бы пойти на бы

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 
+0

Как это отличается от моего? – sawa

+0

@sawa, очевидно, присваивает результаты LOL :) –

1

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

+0

Я не контролирую, как создается Хэш. Поэтому мне придется воссоздать/скопировать только для использования «специального» значения в качестве маркера без ключа. –

12

Рубин 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 

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

  • Нет связанных вопросов^_^