Hängen Sie das Schlüssel / Wert-Paar mit << in Ruby an den Hash an

80

In Ruby können Werte mit <<: an vorhandene Arrays angehängt werden:

a = []
a << "foo"

Können Sie aber auch Schlüssel / Wert-Paare an einen vorhandenen Hash anhängen?

h = {}
h << :key "bar"

Ich weiß, dass Sie Folgendes tun können:

h[:key] = ""
h[:key] << "bar"

aber das will ich nicht.

Vielen Dank.

jcarpio
quelle
20
Warum nicht h[:key] = "bar"?
Hauleth
4
Das funktioniert nicht:h[:key] << "bar"
Chris Nielsen

Antworten:

141

Es gibt merge!.

h = {}
h.merge!(key: "bar")
# => {:key=>"bar"}
sawa
quelle
3
Ich glaube nicht, dass man merge!einfach ein neues Schlüssel / Wert-Paar erstellen kann, da es tatsächlich für einen anderen Zweck verwendet wird.
PericlesTheo
Guter Punkt. Ich denke, es kann auch von anderen Faktoren abhängen, die das OP nicht veröffentlicht hat.
Michael Durrant
1
Ah danke. Sieht so aus, als ob die Speichermethode etwas Ähnliches tut. Dies war hauptsächlich eine akademische Frage, da ich << als eine Möglichkeit zum Anhängen an Arrays gesehen habe, aber sehen wollte, ob es für Hashes funktioniert. Danke noch einmal.
Jcarpio
5
Der Unterschied ist folgender: storeFügt einfach ein neues Paar hinzu, es ist egal, ob der Schlüssel bereits vorhanden ist. mit merge!jedoch Einträge mit Nachschlüssel außer Kraft gesetzt werden , so dass die Methode ein bisschen mehr als nur Paare hinzuzufügen. Wenn Sie die beiden vergleichen, werden Sie feststellen store, dass Sie schneller sind (trivial, jedoch besonders bei kleinen Hashes)
PericlesTheo
2
@jcarpio Danke. Hash#merge!Gibt den Empfänger-Hash genauso zurück wie Array#<<das Empfänger-Array. Hash#storeist eine ganz andere Sache. Mit der Hash-Syntax Zucker key: "bar"in der Argumentationsposition dachte ich auch, dass dies der Punkt ist, den Sie Ihrer Notation am nächsten kommen können. Ich wusste, dass dieser näher an dem ist, was Sie wollten.
Sawa
89

Da Hashes nicht von Natur aus geordnet sind, gibt es keine Vorstellung von Anhängen. Ruby-Hashes seit 1.9 behalten jedoch die Einfügereihenfolge bei. Hier finden Sie Möglichkeiten zum Hinzufügen neuer Schlüssel / Wert-Paare.

Die einfachste Lösung ist

h[:key] = "bar"

Wenn Sie eine Methode wünschen, verwenden Sie store:

h.store(:key, "bar")

Wenn Sie wirklich, wirklich einen "Schaufel" -Operator ( <<) verwenden möchten , wird dieser tatsächlich an den Wert des Hash als Array angehängt, und Sie müssen den Schlüssel angeben:

h[:key] << "bar"

Das Obige funktioniert nur, wenn der Schlüssel vorhanden ist. Um einen neuen Schlüssel anzuhängen, müssen Sie den Hash mit einem Standardwert initialisieren. Dies können Sie folgendermaßen tun:

h = Hash.new {|h, k| h[k] = ''}
h[:key] << "bar"

Sie könnten versucht sein, Hash-Affen zu patchen, um einen Schaufeloperator einzuschließen, der so funktioniert, wie Sie es geschrieben haben:

class Hash
  def <<(k,v)
    self.store(k,v)
  end
end

Dies erbt jedoch nicht den "syntaktischen Zucker", der in anderen Kontexten auf den Schaufeloperator angewendet wird:

h << :key, "bar" #doesn't work
h.<< :key, "bar" #works
Mark Thomas
quelle
Gründlich! Vielen Dank für den Beitrag und den Einblick.
Jcarpio
Ab Ruby 1.9 werden Hashes bestellt.
Stahl
1
Ruby 1.9+ behält die Einfügereihenfolge bei, aber ein Hash als Datenstruktur hat nicht das Konzept einer inhärenten Reihenfolge.
Mark Thomas
26

Nein, ich glaube nicht, dass Sie Schlüssel / Wert-Paare anhängen können. Das einzige, was mir am nächsten kommt , ist die Verwendung der storeMethode:

h = {}
h.store("key", "value")
PericlesTheo
quelle
3

Vielleicht möchten Sie Hash # zusammenführen?

1.9.3p194 :015 > h={}
 => {} 
1.9.3p194 :016 > h.merge(:key => 'bar')
 => {:key=>"bar"} 
1.9.3p194 :017 > 

Wenn Sie das Array an Ort und Stelle ändern möchten, verwenden Sie merge!

1.9.3p194 :016 > h.merge!(:key => 'bar')
 => {:key=>"bar"} 
Michael Durrant
quelle
Ich denke nicht, dass mergees eine gute Idee ist, weil es ein neues Array zurückgibt; Das neue Paar wird nicht zum vorhandenen Hash hinzugefügt.
PericlesTheo
Wie wäre es mit dem merge!(dh zu vorhandenen Array) statt merge?
Michael Durrant
1
merge!Technisch funktioniert dies in diesem Zusammenhang, aber ich denke, es sollte zum Zusammenführen von zwei Hashes verwendet werden, anstatt einfach ein neues Paar hinzuzufügen. Auch wenn Sie Benchmarking ist merge!, ist es langsamer als store;)
PericlesTheo
3

Ähnlich wie sie sind, merge!und storebehandeln bestehende Hashes unterschiedlich auf Keynames abhängig und wird daher Ihre Präferenz beeinflussen. Anders als das aus einer Syntax Sicht merge!‚s key: "value"Syntax entspricht eng gegen JavaScript und Python. Ich persönlich habe es immer gehasst, Schlüssel-Wert-Paare durch Kommas zu trennen.

hash = {}
hash.merge!(key: "value")
hash.merge!(:key => "value")
puts hash

{:key=>"value"}

hash = {}
hash.store(:key, "value")
hash.store("key", "value")
puts hash

{:key=>"value", "key"=>"value"}

Um den Schaufelbediener zum Laufen zu bringen <<, würde ich empfehlen, die Antwort von Mark Thomas zu verwenden .

kayleeFrye_onDeck
quelle
1

Ich musste etwas Ähnliches tun, aber ich musste Werte mit denselben Schlüsseln hinzufügen. Wenn ich Merge oder Update verwende, kann ich keine Werte mit denselben Tasten übertragen. Also musste ich eine Reihe von Hashes verwenden.

    my_hash_static = {:header =>{:company => 'xx', :usercode => 'xx', :password => 'xx',
                      :type=> 'n:n', :msgheader => from}, :body=>[]}
    my_hash_dynamic = {:mp=>{:msg=>message, :no=>phones} }        
    my_hash_full = my_hash_static[:body].push my_hash_dynamic
Caner Çakmak
quelle