Frage

    

Diese Frage bereits eine Antwort hier:

         

Ich dachte, ich verstand, was die Standardmethode funktioniert auf einen Hash ...

einen Standardwert für einen Schlüssel geben, wenn es nicht vorhanden ist:

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = 4
=> 4
irb(main):003:0> a[8]
=> 4
irb(main):004:0> a[9] += 1
=> 5
irb(main):005:0> a
=> {9=>5}

Alle gut.

Aber wenn ich die Standardeinstellung eine leere Liste oder leeren Hash sein, verstehe ich nicht, es ist das Verhalten bei alle ....

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9]                          # great!
irb(main):004:0> a
=> {}                           # ?! would have expected {8=>[9]}
irb(main):005:0> a[8]
=> [9]                          # awesome!
irb(main):006:0> a[9]
=> [9]                          # unawesome! shouldn't this be [] ??

Ich hatte gehofft, / das gleiche Verhalten erwarten, als ob ich die || = Operator benutzt hatte ...

irb(main):001:0> a = {}
=> {}
irb(main):002:0> a[8] ||= []
=> []
irb(main):003:0> a[8] << 9
=> [9]
irb(main):004:0> a
=> {8=>[9]}
irb(main):005:0> a[9]
=> nil

Kann mir jemand erklären, was los ist?

War es hilfreich?

Lösung

Hash.default wird verwendet, um den Standardwert zu setzen zurück , wenn Sie einen Schlüssel abzufragen, die nicht existiert. Ein Eintrag in der Sammlung ist nicht für Sie erstellt haben, nur weil es abgefragt wird.

Auch, stellen Sie den Wert, den Sie default eine Instanz eines Objekts ist (ein Array in Ihrem Fall), so dass, wenn diese zurückgeführt wird, kann sie manipuliert werden.

a = {}
a.default = []     # set default to a new empty Array
a[8] << 9          # a[8] doesn't exist, so the Array instance is returned, and 9 appended to it
a.default          # => [9]
a[9]               # a[9] doesn't exist, so default is returned

Andere Tipps

Dies ist ein sehr nützliches Idiom:

(myhash[key] ||= []) << value

Es kann sogar verschachtelt werden:

((myhash[key1] ||= {})[key2] ||= []) << value

Der andere Weg ist zu tun:

myhash = Hash.new {|hash,key| hash[key] = []}

Das hat aber den erheblichen Nebeneffekt, dass zu fragen über einen Schlüssel wird es schaffen, die has_key macht? ziemlich nutzlos, ich diese Methode so vermeiden.

Ich denke, das ist das Verhalten Sie suchen. Dies wird initialisiert automatisch alle neuen Schlüssel in der Hash in ein Array:

irb(main):001:0> h = Hash.new{|h, k| h[k] = []}
=> {}
irb(main):002:0> h[1] << "ABC"
=> ["ABC"]
irb(main):003:0> h[3]
=> []
irb(main):004:0> h
=> {1=>["ABC"], 3=>[]}

Glenn McDonald's sagt:

"Der andere Weg ist zu tun:

myhash = Hash.new {| hash, key | Hash [key] = []}

Das hat aber den erheblichen Nebeneffekt, dass über einen Schlüssel zu fragen es schaffen wird, die has_key macht? ziemlich nutzlos, so dass diese Methode, die ich vermeiden. "

, die in der Tat scheint nicht wahr zu sein.

irb(main):004:0> a = Hash.new {|hash,key| hash[key] = []}
=> {}
irb(main):005:0> a.has_key?(:key)
=> false
irb(main):006:0> a[:key]
=> []
irb(main):007:0> a.has_key?(:key)
=> true

Zugriff der Schlüssel wird es schaffen, als ich erwarten würde. Lediglich fragen has_key? nicht.

Wenn Sie wirklich wollen, eine endlos tief Hash haben:

endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
endless["deep"]["in"]["here"] = "hello"

Natürlich, wie Glenn Punkte oben aus, wenn Sie dies tun, die has_key? wie es verliert seine Bedeutung immer wahr zurück. Thx für diesen einen jbarnette.

irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9]                          # great!

Mit dieser Aussage haben Sie den Standard geändert; Sie haben nicht ein neues Array und fügte hinzu: „9“ erstellt. An diesem Punkt ist es identisch, wenn Sie dies stattdessen getan hatten:

irb(main):002:0> a.default = [9]
=> [9]

Daher ist es keine Überraschung, dass Sie das jetzt bekommen:

irb(main):006:0> a[9]
=> [9]                          # unawesome! shouldn't this be [] ??

Darüber hinaus ist die ‚<<‘ zugegebene ‚9‘ mit dem Array; es hat es nicht mit dem Hash hinzufügen, die dies erklärt:

irb(main):004:0> a
=> {}                           # ?! would have expected {8=>[9]}

Statt mit .default, was Sie wahrscheinlich in Ihrem Programm tun möchte, ist so etwas wie folgt aus:

# Time to add a new entry to the hash table; this might be 
# the first entry for this key..
myhash[key] ||= []
myhash[key] << value

Ich bin mir nicht sicher, ob dies ist, was Sie wollen, aber Sie können dies tun, um immer ein leeres Array zurück, wenn eine fehlende Raute-Taste abgefragt wird.

h = Hash.new { [] }
h[:missing]
   => []

#But, you should never modify the empty array because it isn't stored anywhere
#A new, empty array is returned every time
h[:missing] << 'entry'
h[:missing]
   => []
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top