2013-07-15 15 views
41

Was für eine kürzere Version dieses ist ?:Wie kann ich mehrere Hash-Werte gleichzeitig abrufen?

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

Notiere die fetch, ich möchte, um einen Fehler zu erhöhen, wenn der Schlüssel nicht existiert.

Es muss kürzere Version davon sein, wie:

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

Es ist OK Active zu verwenden, falls erforderlich.

+0

Eine wichtige und unausgesprochene Frage ist. Was für möchten Sie Werte von Hash zu Vars zuweisen? –

+0

@MichaelSzyndel Ich kann Ihren Kommentar nicht oben analysieren. – sawa

+1

Warum möchten Sie 'from = hash.fetch (: from); to = hash.fetch (: to); '... anstelle von' hash [: from] '? –

Antwort

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

Verwenden Hash des values_at Methode:

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

Dies wird zurückkehren nil für alle Schlüssel, die in der Hash nicht existieren.

+4

Dies entspricht nicht den Anforderungen des OP. – sawa

+0

@MichaelSzyndel Lesen Sie die Frage selbst. – sawa

+0

Es gibt keine solche Methode, die mehrere Keys und Railse-Exceptions für fehlende Keys abruft. Einer der Gründe kann sein - wenn eine Ausnahme ausgelöst werden sollte - wenn der Schlüssel nicht existiert (er kann nicht zugewiesene Variablen für andere Schlüssel hinterlassen) oder nach dem Abrufen aller Schlüssel? Es ist einfach, solche Überprüfung selbst hinzuzufügen, und ich kann keinen Grund wirklich sehen, warum darauf besteht, hier eine Ausnahme zu erheben. –

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

Dies wird einen Fehler auslösen, wie Sie

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

Dies wird das Array zurück.

Aber OP fragte auf einen fehlenden Schlüssel für Fehler ...

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 'wäre falsch, weil ein Schlüssel mit einem 'nil'-Wert existieren könnte. –

+0

Sie haben Recht. Ich habe den Wert und nicht den Schlüssel überprüft. Ich werde für den Schlüssel bearbeiten. – vgoff

+0

'keys.to_a == [: von,: zu,: Name]' ist falsch. Die Reihenfolge spielt hier eine Rolle, aber die Hash-Tasten haben keine bestimmte Reihenfolge. Sie sollten mindestens 'keys.to_a - [: from,: to,: name] == []' sein. Insgesamt ist es mehr Mühe als es wert ist. –

1

Die einfachste Sache, die ich würde

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

Alternativ gehen würde, wenn Sie values_at, verwenden möchten, können Sie verwenden, um ein Hash mit einem Standardwert Block:

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 

Oder wenn Sie so geneigt, Affen-Patch Hash

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

Wie unterscheidet sich das von mir? – sawa

+0

@Sawa offensichtlich, es weist die Ergebnisse LOL :) –

1

Sie könnten Ihre Hash mit einem Standardwert von KeyError Objekt initialisieren. Dadurch wird eine Instanz von KeyError zurückgegeben, wenn der Schlüssel, den Sie abzurufen versuchen, nicht vorhanden ist. Alles, was Sie dann tun müssen, ist seine Klasse (Wert) zu überprüfen und sie zu erhöhen, wenn es sich um einen KeyError handelt.

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

Lassen Sie uns zu diesem Hash sehen einige Daten hinzufügen

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

schließlich die Werte an und einen Fehler auslösen, wenn Schlüssel nicht

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

Dies wird eine Ausnahme ausgelöst, wenn und nur wenn Schlüssel ist nicht vorhanden. Es wird sich nicht beschweren, wenn Sie einen Schlüssel mit nil Wert haben.

+0

Ich kontrolliere nicht, wie der Hash erstellt wird. Also muss ich neu erstellen/kopieren, nur um einen "speziellen" Wert als Marker für Nicht-Schlüssel zu verwenden. –

12

Ruby-2.3 schließlich führt die fetch_values Methode für Hashes, die diese ohne weiteres erreicht:

{a: 1, b: 2}.fetch_values(:a, :b) 
# => [1, 2] 
{a: 1, b: 2}.fetch_values(:a, :c) 
# => KeyError: key not found: :c 
Verwandte Themen