2017-01-13 4 views
1

dynamisch einstellen kann, sollte es einfach sein, aber ich konnte keine richtige Lösung finden. für die erste Ebene Schlüssel:Wie man den Wert des geschachtelten Schlüssels in Ruby Hash

resource.public_send("#{key}=", value) 

aber für foo.bar.lolo?

Ich weiß, dass ich es wie die bekommen kann folgende:

'foo.bar.lolo'.split('.').inject(resource, :send) 

oder

resource.instance_eval("foo.bar.lolo") 

aber, wie der Wert der letzten Variablen setzen unter der Annahme, dass ich weiß nicht, die Verschachtelungsebene es kann zweiter oder dritter sein.

Gibt es einen allgemeinen Weg, dies für alle Ebenen zu tun? für mein Beispiel kann ich es wie folgt tun:

resource.public_send("fofo").public_send("bar").public_send("lolo=", value) 
+0

'resource.public_send (" # {key} = ", Wert)' setzt nichts im Hash. – mudasobwa

+0

Nein, es funktioniert nicht für verschachtelte Schlüssel, die Objekte enthalten. so funktioniert es für 'obj.fofo', aber es funktioniert nie für' bject.fofo.olo', gibt es undefined Methode – user181452

+0

Bitte schreiben Sie einige Fakten und Informationen nicht nur Kritik :) das ist der Punkt der Website, nicht das zu zeigen Du weißt es und ich weiß es nicht. sag mir meine Fehler, es ist viel besser als nur diesen total nutzlosen Kommentar zu geben. Ich kann damit nichts anfangen. – user181452

Antwort

3

Antwort für Hashes, nur aus Neugier:

hash = { a: { b: { c: 1 } } } 
def deep_set(hash, value, *keys) 
    keys[0...-1].inject(hash) do |acc, h| 
    acc.public_send(:[], h) 
    end.public_send(:[]=, keys.last, value) 
end 

deep_set(hash, 42, :a, :b, :c) 
#⇒ 42 
hash 
#⇒ { a: { b: { c: 42 } } } 
+0

ist das nicht das gleiche wie Hash # begraben? d. h. [dies] (https://github.com/dam13n/ruby-bury) –

+0

@maxple Ich habe keine Ahnung, was "begraben" ist. Das ist reiner Rubin. – mudasobwa

+0

ist es wie die Nebenstelle zu graben. Wie der Edelstein, den ich verlinkt habe. Ich sage nur, dass Leute diese Funktionalität gewöhnlich begraben. –

0

Hashes in Ruby nicht standardmäßig geben Sie diese Punkt Methoden.

Sie können Anrufe Kette senden (das auf ein beliebiges Objekt funktioniert, aber man kann nicht Hash-Schlüssel auf diese Weise normalerweise Zugriff):

"foo".send(:downcase).send(:upcase) 

Wenn mit verschachtelten Hashes der schwierige Konzept der Veränderlichkeit Arbeit relevant ist. Zum Beispiel:

hash = { a: { b: { c: 1 } } } 
    nested = hash[:a][:b] 
    nested[:b] = 2 
    hash 
    # => { a: { b: { c: 2 } } 

„Veränderlichkeit“ bedeutet hier, dass, wenn Sie die verschachtelte Hash in eine separate Variable speichern, ist es eigentlich noch ein Zeiger auf den ursprünglichen Hash ist. Mutabilität ist nützlich für eine Situation wie diese, aber es kann auch Fehler verursachen, wenn Sie es nicht verstehen.

Sie können :a oder :b Variablen zuweisen, um es in gewisser Weise "dynamisch" zu machen.

Es gibt erweiterte Möglichkeiten, wie in neueren Rubin

versions. 

    hash = { a: { b: { c: 1 } } } 
    keys_to_get_nested_hash = [:a, :b] 
    nested_hash = hash.dig *keys_to_get_nested_hash 
    nested_hash[:c] = 2 
    hash 
    # => { a: { b: { c: 2 } } } 

zu tun Wenn Sie OpenStruct verwenden, dann können Sie Ihre Hashes geben Punkt-Methode Accessoren. Um ehrlich zu sein Verkettung send Anrufe ist nicht etwas, das ich oft verwendet habe. Wenn es Ihnen hilft, Code zu schreiben, ist das großartig. Sie sollten jedoch keine vom Benutzer generierten Eingaben senden, da dies unsicher ist.

+2

'hash.public_send (: [],: a) .public_send (: [] =,: b, 42)' funktioniert perfekt, es gibt nichts Schwieriges. – mudasobwa

0

Obwohl Sie einige Methoden implementieren könnten die Dinge so, wie Sie sie jetzt einrichten zu tun haben, würde ich empfehlen, dass Sie Ihre Daten überdenken Strukturen.

Um einige Ihrer Terminologie zu klären, ist die key in Ihrem Beispiel kein Schlüssel, sondern ein Methodenaufruf. In Ruby, wenn Sie Code wie my_thing.my_other_thing haben, ist my_other_thing IMMER eine Methode und NIE ein Schlüssel, zumindest nicht im eigentlichen Sinne des Begriffs.

Es ist wahr, dass Sie eine Hash-ähnliche Struktur erstellen können, indem Sie Objekte auf diese Weise verketten, aber es gibt einen echten Code-Geruch dazu.Wenn Sie sich foo.bar.lolo als eine Möglichkeit vorstellen, den verschachtelten Schlüssel lolo in einem Hash nachzuschlagen, sollten Sie wahrscheinlich einen regulären Hash verwenden.

x = {foo: {bar: 'lolo'}} 
x[:foo][:bar] # => 'lolo' 
x[:foo][:bar] = 'new_value' # => 'new_value' 

Auch, obwohl die Sende-/instance_eval Methoden auf diese Weise verwendet werden können, ist es nicht die beste Praxis und Sicherheitsprobleme selbst erstellen kann.

Verwandte Themen