Wenn in Ruby Hash [: a] [: b] [: c] = 0 ist, möchten wir, dass Sie rekursiv erweitern, auch wenn der Schlüssel nicht vorhanden ist

TL;DR

Ich möchte so etwas wie "mkdir -p" von unix mit einem Ruby-Hash machen

hash = Hash.new {|h,k| h[k] = h.class.new(&h.default_proc) }
hash[:a][:b][:c] = 'Good!!'
p hash # {:a=>{:b=>{:c=>"Good!!"}}}

Kommentar

Über Hash.new

Hash.new nimmt den Hash selbst und den Schlüssel und der Block kann einen Standardwert definieren, wenn der Inhalt des Schlüssels nicht vorhanden ist.

hash1 = Hash.new { |h, k| 0 }

hash1[:a] = 100
p hash1[:a] # 100
p hash1[:b] # 0

Das Obige definiert einfach einen Hash, der 0 zurückgibt, wenn der Schlüssel nicht gefunden wird. Da : a gesetzt ist, bezieht es sich auf den Inhalt des Hashs, und da: b nicht existiert, wird der Block ausgeführt und 0 zurückgegeben.

Legen Sie einen Standardwert für den Hash fest

Wenn Sie die Eigenschaft nutzen, dass der Block nur ausgeführt wird, wenn der Schlüssel nicht gefunden wird, können Sie den Standardwert wie folgt auf den Hash selbst anwenden.

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

hash2[:a] += 100
hash2[:b] += 200

p hash2 # {:a=>100, :b=>200}

Im Folgenden wird, da beide : a``: b undefiniert sind, die Additionsverarbeitung mit+ =durchgeführt, aber wenn hash2 [: a] hash2 [: b] ausgewertet wird Der Standardwert 0 wird im Hash selbst festgelegt, sodass 100 und 200 hervorragend eingestellt sind.

Erweitern Sie den Hash mit Standardwerten

Mit einer weiteren Anwendung können Sie einen Hash auch dann graben, wenn die Schlüssel verschachtelt sind.

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

hash3[:a][:b] = 100
p hash3 # {:a=>{:b=>100}

Der Block wird ausgeführt, wenn auf "hash3 [: a]" verwiesen wird, und der Hash nach "hash3 [: a] = {}" wird zurückgegeben. Andererseits wird "[: b] = 100" ausgeführt, sodass der endgültige verschachtelte Hash erstellt wird.

Wenn dies jedoch unverändert bleibt, schlägt es fehl, wenn die Verschachtelung verdreifacht wird.

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

hash3[:a][:b][:c] = 100 # undefined method `[]=' for nil:NilClass (NoMethodError)

Das liegt daran, dass "hash3 [: a]" den Standardwert festlegt, aber es ist nur ein "{}", das selbst keine Standardwerteinstellung definiert.

Daher ist "hash3 [: a] [: b]" nur ein Hash ohne Standardwert. Wenn Sie also versuchen, auf "hash3 [: a] [: b] [: c]" zu verweisen, wird eine Fehlermeldung angezeigt. ist.

Erweitern Sie den Hash "rekursiv" mit Standardwerten

Der hash3 [: a] [: b] im vorherigen Abschnitt ist zu einem normalen Hash ohne Standardwert geworden, aber ich möchte, dass er einen ähnlichen Standardwert hat.

Um es einfach zu schreiben, ist es wie folgt.

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

hash4[:a][:b][:c] = 100
p hash4 # {:a=>{:b=>{:c=>100}}}

Wir konnten sogar dreifach verschachteln. Es kann jedoch natürlich keine Vierfachverschachtelung unterstützen. Es ist die Hölle.

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)

Unabhängig davon, wie tief die Verschachtelung ist, soll der Hash der Standardwert sein, der den Standardwert rekursiv fest definiert.

Sie können [Hash # default_proc] verwenden (https://docs.ruby-lang.org/ja/latest/method/Hash/i/default_proc.html). default_proc kann den Block der Standardwertdefinition abrufen, der im Hash mit dem Objekt proc festgelegt ist.

proc kann mit der call -Methode ausgeführt werden. Wenn Sie sich also Folgendes ansehen, erhalten Sie ein Bild.

hash5 = Hash.new { |k, v| 'default value'}

p hash5.default_proc.call(nil, nil) # "default value"

Und der Block kann in der Form "& proc" übergeben werden, so dass Sie ihn wie folgt schreiben können:

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

Hast du Hunger bekommen?

hash6 macht Hash, das die Definition seines eigenen Standardwerts auf seinen eigenen Standardwert anwendet. Dies bedeutete, dass die Definition des Standardwerts immer vererbt wurde, egal wie viele Nester es gab.

Bemerkungen

Nachdem ich es geschrieben hatte, bemerkte ich, dass es einen Artikel mit einem Kommentar zu einer ähnlichen Geschichte gab. Nun, ich werde es im Sinne der Organisation des Gelernten veröffentlichen.

Recommended Posts

Wenn in Ruby Hash [: a] [: b] [: c] = 0 ist, möchten wir, dass Sie rekursiv erweitern, auch wenn der Schlüssel nicht vorhanden ist
MockMVC gibt 200 zurück, auch wenn ich eine Anfrage an einen Pfad stelle, der nicht existiert
Ich möchte eine Parkettdatei auch in Ruby erstellen
Ich möchte das Flash-Attribut im Frühjahr, auch wenn ich einen Reverse-Proxy festgelegt habe! (TU es nicht)
[Ruby] Ich möchte nur den Wert des Hash und nur den Schlüssel extrahieren
Ich möchte den Wert in Ruby erhalten
Auch wenn ich den Inhalt eines Datenobjekts in Java in JSON konvertieren möchte, gibt es einen Zirkelverweis ...
Was tun, wenn Sie Ruby mit rbenv installiert haben, die Version sich jedoch nicht ändert?
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben
Selbst wenn ich die Einstellung von STRICT_QUOTE_ESCAPING in CATALINA_OPTS in tomcat8.5 schreibe, wird sie nicht wiedergegeben.
[Ruby] Ich möchte die Reihenfolge der Hash-Tabelle umkehren
Was tun, wenn Sie in Eclipse eine JRE auswählen und "Die ausgewählte JRE unterstützt die aktuelle Konformitätsstufe 11 nicht" erhalten?
Wenn Sie eine Methode in RSpec verspotten möchten, sollten Sie die Methode allow für mock und die Singleton-Methode verwenden.
Wenn Sie die übergeordnete Klasse in Lomboks @builder aufnehmen möchten
[Java] Ich möchte mit dem Schlüssel im Objekt eindeutig arbeiten
Ich möchte den Wert von Attribute in Selenium of Ruby ändern
Wenn ich ein Gem mit C-Erweiterung in Ruby installiere, möchte ich es schnell mit mehreren CPU-Kernen wie make -j4 fertigstellen
Ich möchte eine Datei mit Ruby im Internet herunterladen und lokal speichern (mit Vorsicht).
Ein aktiver Hash, der als Daten behandelt werden kann, auch wenn er nicht in der Datenbank enthalten ist
Eine Geschichte, die selbst ein Mann, der die C-Sprache nicht versteht, Ruby 2.6 um neue Funktionen erweitern könnte
Was tun, wenn der Vorgang nicht zulässig ist, wenn ein Befehl im Terminal ausgeführt wird?
Was tun, wenn das Präfix c in JSP nicht gebunden ist?
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben (PowerMockito Edition)
Wenn Sie mit Ruby eine Zip-Datei erstellen möchten, ist dies Rubyzip.
Ich möchte, dass Sie Enum # name () für den Schlüssel von SharedPreference verwenden
Aktualisieren Sie, wenn das Dokument bereits im Azure Cosmos DB Java SDK vorhanden ist, und erstellen Sie ein neues Dokument, wenn es nicht vorhanden ist
Fortsetzung ・ Aktiver Hash, der als Daten behandelt werden kann, auch wenn er nicht in der Datenbank enthalten ist ~ Anzeige
Wenn Sie die Testabdeckung privater Methoden in JUnit erfüllen möchten
So funktioniert @Transactional, das nicht funktioniert, wenn Sie es falsch verwenden
Sogar in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben (Javassist zweite Abkochung)
Möglicherweise möchten Sie die Methode remove in ArrayList nicht sehr oft verwenden
Ich möchte rekursiv die Oberklasse und die Schnittstelle einer bestimmten Klasse erhalten
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 (Black Magic) ausgeben.
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben (graue Magie, die weniger schwarze Magie ist)
[Ruby] Ich möchte einen Methodensprung machen!
Ich habe eine Ruby-Erweiterungsbibliothek in C erstellt
Ich möchte irgendwann sogar in Kotlin sein
Ich möchte das in der Datenbank gespeicherte Protokoll morphologisch analysieren und in der Datenbank speichern, um Nachrichten 1 zu klassifizieren
[Rails] Ich möchte das Linkziel von link_to auf einer separaten Registerkarte anzeigen
7 Dinge, die du behalten sollst, damit es kein verdammter Code wird
[Maven] Was tun, wenn Sie aufgefordert werden, ein Glas, das sich nicht im Remote-Repository befindet, in den Krieg aufzunehmen?
Zum Zeitpunkt des dialogReturn-Ereignisses habe ich überprüft, ob es nicht aktualisiert wird, auch wenn ich eine Komponente mit Aktualisierung angegeben habe
Ich möchte eine TraceId in das Protokoll einbetten
Ich möchte ein kleines Symbol in Rails verwenden
AtCoder Anfängerwettbewerb 170 A, B, C bis Rubin
Ich möchte eine Funktion in der Rails Console definieren
Ich möchte in RSpec auf einen GoogleMap-Pin klicken
Ich möchte der Kommentarfunktion eine Löschfunktion hinzufügen
Nachdem ich einen Artikel mit Rails Simple Calendar veröffentlicht habe, möchte ich ihn im Kalender wiedergeben.