2008-10-04 12 views
34

Das Erstellen von Hashes von Hashes in Ruby ermöglicht bequeme zwei (oder mehr) dimensionale Lookups. Beim Einfügen muss jedoch immer geprüft werden, ob der erste Index bereits im Hash existiert. Zum Beispiel:Hashes of Hashes Idiom in Ruby?

h = Hash.new 
h['x'] = Hash.new if not h.key?('x') 
h['x']['y'] = value_to_insert 

Es wäre besser, die folgend, wo der neue Hash zu tun automatisch erstellt wird:

h = Hash.new 
h['x']['y'] = value_to_insert 

ähnlich, wenn die Suche nach einem Wert, wo der erste Index nicht bereits vorhanden ist, Es wäre vorzuziehen, wenn nil zurückgegeben wird, anstatt eine undefinierte Methode für den Fehler '[]' zu erhalten.

looked_up_value = h['w']['z'] 

Man könnte eine Hash-Wrapper-Klasse erstellen, die dieses Verhalten hat, aber gibt es ein bestehendes Ruby Idiom diese Aufgabe für die Erfüllung?

+0

Gibt es einen Hash von Hash-Idiomen, die nach einer bestimmten Tiefe 0 zurückgeben würden? (Ich zähle Dinge und ich benutze h [: foo] [: bar] [: baz] + = 1) –

Antwort

54

Sie können die Hash.new Funktion einen Block übergeben, die einen Standardwert, falls der abgefragte Wert existiert noch nicht erhalten wird ausgeführt:

h = Hash.new { |h, k| h[k] = Hash.new } 

Natürlich ist diese rekursiv durchgeführt werden kann.

/BEARBEITEN: Wow, es gibt an article, die diese sehr Frage beantworten.

Aus Gründen der Vollständigkeit, hier ist die Lösung aus dem Artikel für beliebige Tiefe Hashes:

hash = Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)})) 

Credits Kent geht von Data Noise.

+1

Wow. Das ist beeindruckend. –

+0

Toter Link. Beeindruckende Lösung. –

+1

Der tote Link ist hier geschaltet http://inquirylabs.com/blog2009/2006/09/20/ruby-hashes-of-arbitrary-depth/ – Autodidact

4

Autovivification, wie es genannt wird, ist sowohl ein Segen als auch ein Fluch. Das Problem kann sein, dass Sie, wenn Sie auf einen Wert "schauen", bevor er definiert ist, mit diesem leeren Hash im Slot stecken bleiben und ihn später wieder entfernen müssen.

Wenn Sie nicht ein bisschen Anarchie ausmacht, kann man immer nur Marmelade in oder-gleich-Stylesheets, die Sie die erwartete Struktur konstruieren können, wie Sie es abfragen:

((h ||= { })['w'] ||= { })['z']