40 votes

Définir ruby hash .default à une liste

Je pensais comprendre ce que la méthode par défaut fait d'un hachage ...

Donnez une valeur par défaut pour une clé si elle n'existe pas:

 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}
 

Tout bon.

Mais si je mets la valeur par défaut à une liste vide ou hachage vide, je ne comprends pas son comportement du tout ....

 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]
=> [8]                          # awesome!
irb(main):006:0> a[9]
=> [9]                          # unawesome! shouldn't this be [] ??
 

J'espérais / m'attendais au même comportement que si j'avais utilisé l'opérateur || = ...

 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
 

Quelqu'un peut-il expliquer ce qui se passe?

52voto

glenn mcdonald Points 8933

C'est un idiome très utile:

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

Il peut même être imbriqué:

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

L'autre façon est de faire:

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

Mais ceci a pour effet secondaire significatif que poser une question sur une clé la créera, qui rend has_key? assez inutile, alors j'évite cette méthode.

49voto

Aaron Hinni Points 7879

Hash.default est utilisé pour définir la valeur par défaut renvoyée lorsque vous interrogez une clé inexistante. Une entrée de la collection n'est pas créée pour vous, mais simplement parce qu'elle a été interrogée.

De plus, la valeur que vous définissez default est une instance d'un objet (un tableau dans votre cas). Ainsi, lorsque cela est renvoyé, il peut être manipulé.

 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
 

33voto

Turp Points 295

Je pense que c'est le comportement que vous recherchez. Cela initialisera automatiquement toutes les nouvelles clés du hachage sur un tableau:

 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=>[]}
 

9voto

migbar Points 96

Si vous voulez vraiment un hachage infiniment profond:

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

Bien sûr, comme le souligne Glenn ci-dessus, si vous faites cela, la has_key? perd son sens car il retournera toujours vrai. Merci à jbarnette pour celui-ci.

9voto

jrochkind Points 4170

Glenn McDonald dit:

"L'autre façon est de faire:

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

Mais ceci a pour effet secondaire significatif que poser une question sur une clé la créera, qui rend has_key? assez inutile, alors j’évite cette méthode. "

cela ne semble en fait pas être vrai.

 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
 

L'accès à la clé le créera, comme je m'y attendais. Simplement demander has_key? ne fait pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X