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