Si hash [: a] [: b] [: c] = 0 dans Ruby, je veux que vous étendiez récursivement même si la clé n'existe pas

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!!"}}}

Commentaire

À propos de Hash.new

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é.

Définir une valeur par défaut pour le hachage

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.

Étendre le hachage avec les valeurs par défaut

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.

Étendre le hachage «récursivement» avec les valeurs par défaut

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.

Remarques

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.

Recommended Posts

Si hash [: a] [: b] [: c] = 0 dans Ruby, je veux que vous étendiez récursivement même si la clé n'existe pas
MockMVC renvoie 200 même si je fais une demande vers un chemin qui n'existe pas
Je veux créer un fichier Parquet même en Ruby
Je veux FlashAttribute au printemps même si j'ai défini un proxy inverse! (ne pas faire)
[Ruby] Je souhaite extraire uniquement la valeur du hachage et uniquement la clé
Je veux obtenir la valeur en Ruby
Même si je souhaite convertir le contenu d'un objet de données en JSON en Java, il existe une référence circulaire ...
Que faire si vous avez installé Ruby avec rbenv mais que la version ne change pas
Même en Java, je veux afficher true avec un == 1 && a == 2 && a == 3
Même si j'écris le paramètre de STRICT_QUOTE_ESCAPING dans CATALINA_OPTS dans tomcat8.5, il n'est pas reflété.
[Ruby] Je souhaite inverser l'ordre de la table de hachage
Que faire si vous sélectionnez un JRE dans Eclipse et obtenez "Le JRE sélectionné ne prend pas en charge le niveau de conformité actuel 11"
Si vous souhaitez simuler une méthode dans RSpec, vous devez utiliser la méthode allow pour mock et la méthode singleton.
Si vous souhaitez inclure la classe parente dans @builder de Lombok
[Java] Je veux effectuer distinctement avec la clé dans l'objet
Je veux changer la valeur de l'attribut dans Selenium of Ruby
Lors de l'installation d'un gem avec l'extension C dans Ruby, je veux le terminer rapidement en utilisant plusieurs cœurs de processeur comme make -j4
Je souhaite télécharger un fichier sur Internet en utilisant Ruby et l'enregistrer localement (avec prudence)
Un hachage actif qui peut être traité comme des données même s'il n'est pas dans la base de données
Une histoire que même un homme qui ne comprend pas le langage C pourrait ajouter de nouvelles fonctions à Ruby 2.6
Que faire si l'opération non autorisée s'affiche lors de l'exécution d'une commande dans le terminal
Que faire lorsque le préfixe c n'est pas lié dans JSP
Même en Java, je veux afficher true avec un == 1 && a == 2 && a == 3 (édition PowerMockito)
Si vous voulez créer un fichier zip avec Ruby, c'est rubyzip.
Je veux que vous utilisiez Enum # name () pour la clé de SharedPreference
Mettre à jour si le document existe déjà dans le SDK Java Azure Cosmos DB, en créer un s'il n'existe pas
Continuation ・ Hash actif qui peut être traité comme des données même s'il n'est pas dans la base de données ~ Affichage
Si vous souhaitez satisfaire la couverture de test des méthodes privées dans JUnit
Comment faire fonctionner @Transactional qui ne fonctionne pas si vous ne l'utilisez pas correctement
Même en Java, je veux sortir true avec un == 1 && a == 2 && a == 3 (deuxième décoction Javassist)
Vous pouvez ne pas vouloir utiliser la méthode remove sur ArrayList très souvent
Je veux obtenir récursivement la superclasse et l'interface d'une certaine classe
Même en Java, je veux afficher true avec un == 1 && a == 2 && a == 3 (Black Magic)
Même en Java, je veux sortir vrai avec un == 1 && a == 2 && a == 3 (magie grise qui n'est pas tant que magie noire)
[Ruby] Je veux faire un saut de méthode!
J'ai créé une bibliothèque d'extension Ruby en C
Je veux être finalement même à kotlin
Je souhaite analyser morphologiquement le journal stocké dans la base de données et le stocker dans la base de données pour classer les messages 1
[Rails] Je souhaite afficher la destination du lien de link_to dans un onglet séparé
7 choses que je veux que tu gardes pour que ça ne devienne pas un putain de code
[Maven] Que faire si on vous demande d’incorporer dans la guerre un fichier jar qui n’est pas dans le référentiel distant
Au moment de l'événement dialogReturn, j'ai vérifié car il n'est pas mis à jour même si je spécifie un composant avec mise à jour
Je veux intégrer n'importe quel TraceId dans le journal
Je veux utiliser une petite icône dans Rails
AtCoder Beginner Contest 170 A, B, C jusqu'au rubis
Je souhaite définir une fonction dans la console Rails
Je veux cliquer sur une broche GoogleMap dans RSpec
Je souhaite ajouter une fonction de suppression à la fonction de commentaire
Après avoir publié un article avec Rails Simple Calendar, je souhaite le refléter dans le calendrier.