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?

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}

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)

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

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"}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.