TL;DR
Je veux faire quelque chose comme mkdir -p
d'Unix avec un hachage Ruby
hash = Hash.new {|h,k| h[k] = h.class.new(&h.default_proc) }
hash[:a][:b][:c] = 'Good!!'
p hash # {:a=>{:b=>{:c=>"Good!!"}}}
Hash.new
prend le hachage lui-même et la clé, et le bloc peut définir une valeur par défaut si le contenu de la clé n'existe pas.
hash1 = Hash.new { |h, k| 0 }
hash1[:a] = 100
p hash1[:a] # 100
p hash1[:b] # 0
Ce qui précède définit simplement un hachage qui renvoie 0 si la clé n'est pas trouvée. Puisque : a
est défini, il fait référence au contenu du hachage, et comme: b
n'existe pas, le bloc est exécuté et 0 est retourné.
Tirant parti de la propriété selon laquelle le bloc est exécuté uniquement lorsque la clé n'est pas trouvée, vous pouvez appliquer la valeur par défaut au hachage lui-même comme suit.
hash2 = Hash.new { |h, k| h[k] = 0 }
hash2[:a] += 100
hash2[:b] += 200
p hash2 # {:a=>100, :b=>200}
Dans ce qui suit, puisque les deux : a``: b
ne sont pas définis, le traitement d'addition est effectué en utilisant+ =
, mais lorsquehash2 [: a] `` hash2 [: b]
est évalué La valeur par défaut de 0 est définie dans le hachage lui-même, donc 100 et 200 sont définis avec brio.
Une application supplémentaire vous permet de creuser un hachage même lorsque les clés sont imbriquées.
hash3 = Hash.new { |h,k| h[k] = {} }
hash3[:a][:b] = 100
p hash3 # {:a=>{:b=>100}
Le bloc est exécuté lorsque hash3 [: a]
est référencé, et le hachage après l'application de hash3 [: a] = {}
est retourné. D'un autre côté, «[: b] = 100» est exécuté, donc le hachage imbriqué final est créé.
Cependant, si cela est laissé tel quel, il échouera si l'imbrication est triplée.
hash3 = Hash.new { |h,k| h[k] = {} }
hash3[:a][:b][:c] = 100 # undefined method `[]=' for nil:NilClass (NoMethodError)
C'est parce que hash3 [: a]
définit la valeur par défaut, mais c'est juste un {}
, qui lui-même ne définit pas de valeur par défaut.
Par conséquent, hash3 [: a] [: b]
est juste un hachage sans valeur par défaut, donc si vous essayez de faire référence à hash3 [: a] [: b] [: c]
, vous obtiendrez une erreur. est.
Le hash3 [: a] [: b]
dans la section précédente est devenu un hachage normal sans valeur par défaut, mais je voudrais qu'il ait une valeur par défaut similaire.
Pour l'écrire simplement, c'est comme suit.
hash4 = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = {} } }
hash4[:a][:b][:c] = 100
p hash4 # {:a=>{:b=>{:c=>100}}}
Nous avons pu gérer même une triple nidification. Cependant, bien sûr, il ne peut pas prendre en charge l'imbrication quadruple. C'est l'enfer.
hash4 = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = {} } }
hash4[:a][:b][:c][:d] = 100 # undefined method `[]=' for nil:NilClass (NoMethodError)
Quelle que soit la profondeur de l'imbrication, nous voulons que le hachage soit la valeur par défaut, qui définit de manière récursive la valeur par défaut.
Vous pouvez utiliser Hash # default_proc. default_proc
peut obtenir le bloc de définition de valeur par défaut défini dans le hachage avec l'objet proc
.
proc
peut être exécuté par la méthode call
, donc si vous regardez ce qui suit, vous obtiendrez une image.
hash5 = Hash.new { |k, v| 'default value'}
p hash5.default_proc.call(nil, nil) # "default value"
Et comme le bloc peut être passé sous la forme & proc
, il peut être écrit comme suit:
hash6 = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
hash6[:a][:b][:c][:d] = 100
p hash6 # hash6[:a][:b][:c][:d] = 100
Avez-vous eu faim?
hash6
crée Hash
, qui applique la définition de sa propre valeur par défaut
, à sa propre valeur par défaut
.
Cela signifiait que la définition de la valeur par défaut serait toujours héritée, quel que soit le nombre de nids.
Après l'avoir écrit, j'ai remarqué qu'il y avait un article avec un commentaire sur une histoire similaire. Eh bien, je le posterai dans le sens d'organiser ce que j'ai appris.