Rails ordnet ein Array von Hashes einem einzelnen Hash zu

91

Ich habe eine Reihe von Hashes wie folgt:

 [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]

Und ich versuche dies auf einen einzelnen Hash wie folgt abzubilden:

{"testPARAM2"=>"testVAL2", "testPARAM1"=>"testVAL1"}

Ich habe es mit erreicht

  par={}
  mitem["params"].each { |h| h.each {|k,v| par[k]=v} } 

Aber ich habe mich gefragt, ob es möglich ist, dies auf eine idiomatischere Weise zu tun (vorzugsweise ohne Verwendung einer lokalen Variablen).

Wie kann ich das machen?

Bart Platak
quelle

Antworten:

158

Sie könnten komponieren Enumerable#reduceund Hash#mergeerreichen, was Sie wollen.

input = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
input.reduce({}, :merge)
  is {"testPARAM2"=>"testVAL2", "testPARAM1"=>"testVAL1"}

Das Reduzieren eines Arrays ähnelt dem Einfügen eines Methodenaufrufs zwischen die einzelnen Elemente.

Zum Beispiel [1, 2, 3].reduce(0, :+)ist wie sagen 0 + 1 + 2 + 3und gibt6 .

In unserem Fall machen wir etwas Ähnliches, aber mit der Zusammenführungsfunktion, die zwei Hashes zusammenführt.

[{:a => 1}, {:b => 2}, {:c => 3}].reduce({}, :merge)
  is {}.merge({:a => 1}.merge({:b => 2}.merge({:c => 3})))
  is {:a => 1, :b => 2, :c => 3}
cjhveal
quelle
1
Danke, das ist eine großartige Antwort :) Sehr schön erklärt!
Bart Platak
40
input.reduce (&: merge) ist ausreichend.
redgetan
@redgetan ist das anders als input.reduce(:merge)?
David van Geest
1
@ David van Geest: In diesem Fall sind sie gleichwertig. Das hier verwendete unäre kaufmännische Und bildet einen Block aus dem Symbol. Reduzieren hat jedoch einen Sonderfall, der ein Symbol akzeptiert. Ich wollte den unären kaufmännischen Und-Operator vermeiden, um das Beispiel zu vereinfachen, aber redgetan ist richtig, dass der Anfangswert in diesem Fall optional ist.
cjhveal
1
Beachten Sie, dass bei Verwendung merge!stattdessen mergeder erste Hash geändert wird (den Sie möglicherweise nicht möchten), jedoch nicht für jede neue Zusammenführung ein Zwischen-Hash erstellt wird.
Phrogz
50

Wie wäre es mit:

h = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
r = h.inject(:merge)
Shigeya
quelle
Dieses Schema entspricht praktisch dem, was Joshua geantwortet hat, wendet jedoch wiederholt #merge (als Symbol übergebener Methodenname) auf alle Hashes an (stellen Sie sich injizieren als Injizieren eines Operators zwischen Elementen vor). Siehe #inject .
Shigeya
2
Wieso brauchen wir das kaufmännische Und nicht wie in h.inject (&: merge)?
Donato
5
Weil die Inject-Methode ein Symbol als Parameter akzeptiert, der auch als Methodenname interpretiert werden soll. Es ist die Funktion von Inject.
Shigeya
9

Verwenden Sie #inject

hashes = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
merged = hashes.inject({}) { |aggregate, hash| aggregate.merge hash }
merged # => {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
Joshua Cheek
quelle
0

Hier können Sie entweder injizieren oder aus der Enumerable- Klasse reduzieren, da beide Aliase voneinander sind, sodass auch keine Leistungsvorteile bestehen.

 sample = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]

 result1 = sample.reduce(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}

 result2 = sample.inject(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
Nikhil Mohadikar
quelle