2013-07-15 12 views
41

Czym jest krótsza wersja tego ?:Jak pobrać wiele wartości mieszania naraz?

from = hash.fetch(:from) 
to = hash.fetch(:to) 
name = hash.fetch(:name) 
# etc 

Zanotować fetch, chcę podnieść błąd, jeśli klucz nie istnieje.

Tam musi być krótsza wersja tego, jak:

from, to, name = hash.fetch(:from, :to, :name) # <-- imaginary won't work 

Jest OK, aby użyć ActiveSupport razie potrzeby.

+0

Jednym z ważnych i nieproszony pytanie brzmi. Do czego chcesz zmienić przypisanie wartości z hasha na vars? –

+0

@MichaelSzyndel Nie mogę zanalizować Twojego komentarza powyżej. – sawa

+1

Dlaczego chcesz zrobić 'from = hash.fetch (: from); to = hash.fetch (: to); '... zamiast używać' hash [: from] '? –

Odpowiedz

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

Skorzystaj hash za values_at metoda:

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

ten powróci nil żadnych kluczy, które nie istnieją w hash.

+4

To nie spełnia wymagań PO. – sawa

+0

@MichaelSzyndel Przeczytaj to pytanie samodzielnie. – sawa

+0

Nie ma takiej metody, która pobierze wiele kluczy i wyjątków railse dla brakujących. Jednym z powodów może być - kiedy wyjątek powinien zostać podniesiony - kiedy klucz nie istnieje (może pozostawić nieprzypisane zmienne dla innych kluczy) lub po pobraniu wszystkich kluczy? Łatwo jest dodać takie sprawdzanie samemu i nie widzę żadnego powodu, dla któregobym nalegał na podniesienie wyjątku. –

2
my_array = {from: 'Jamaica', to: 'St. Martin'}.values_at(:from, :to, :name) 
my_array.keys.any? {|key| element.nil?} && raise || my_array 

To podniesie błąd jak prosiłeś

my_array = {from: 'Jamaica', to: 'St. Martin', name: 'George'}.values_at(:from, :to, :name) 
my_array.keys.any? {|key| element.nil?} && raise || my_array 

ta zwróci tablicę.

Ale PO poprosił o braku na brakujący klucz ...

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 | element.nil?} && raise' byłoby niepoprawne, ponieważ klucz może istnieć z wartością 'nil'. –

+0

Masz rację. Sprawdziłem wartość zamiast klucza. Będę edytować klucz. – vgoff

+0

'keys.to_a == [: from,: to,: name]' jest niepoprawne. Kolejność będzie miała znaczenie tutaj, ale klawisze skrótu nie mają określonej kolejności. Powinno to być przynajmniej 'keys.to_a - [: from,: to,: name] == []'. Ogólnie rzecz biorąc, to po prostu więcej wysiłku, niż jest to warte. –

1

Najprostszą rzeczą, jaką chciałbym pójść byłoby

from, to, name = [:from, :to, :name].map {|key| hash.fetch(key)} 

Ewentualnie, jeśli chcesz używać values_at, można używać Hash z bloku wartości domyślne:

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 

Lub, jeśli jesteś tak pochylona, ​​małpa-łata Hash

class ::Hash 
    def fetch_all(*args) 
    args.map {|key| fetch(key)} 
    end 
end 
from, to, name = hash.fetch_all :from, :to, :name 
+0

Czym to się różni od mojego? – sawa

+0

@sawa oczywiście przydziela wyniki LOL :) –

1

Można zainicjować swój hash z domyślnej wartości KeyError obiektu. Spowoduje to zwrócenie instancji KeyError, jeśli klucz, który próbujesz pobrać, nie istnieje. Wszystko, co musisz zrobić, to sprawdzić jego klasę (value) i podnieść ją, jeśli jest to KeyError.

hash = Hash.new(KeyError.new("key not found")) 

Dodajmy jakieś dane na ten hash

hash[:a], hash[:b], hash[:c] = "Foo", "Bar", nil 

Wreszcie spojrzeć na wartości i zgłosi błąd, jeśli nie znaleziono klucza

hash.values_at(:a,:b,:c,:d).each {|v| raise v if v.class == KeyError} 

to podniesie wyjątek, jeśli i tylko wtedy, klucz nie jest obecny. Nie będzie narzekać, jeśli masz klucz o wartości nil.

+0

Nie kontroluję sposobu tworzenia skrótu. Tak więc będę musiał odtworzyć/skopiować tylko po to, aby użyć "specjalnej" wartości jako znacznika braku klucza. –

12

Ruby 2.3 wreszcie wprowadza metodę fetch_values dla skrótów, które wprost osiąga to:

{a: 1, b: 2}.fetch_values(:a, :b) 
# => [1, 2] 
{a: 1, b: 2}.fetch_values(:a, :c) 
# => KeyError: key not found: :c 
Powiązane problemy