Szyny mapujące tablicę skrótów na pojedynczy hash

94

Mam tablicę takich skrótów:

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

I próbuję odwzorować to na pojedynczy hash w następujący sposób:

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

Osiągnąłem to za pomocą

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

Ale zastanawiałem się, czy można to zrobić w bardziej idiomatyczny sposób (najlepiej bez użycia zmiennej lokalnej).

Jak mogę to zrobić?

Bart Platak
źródło

Odpowiedzi:

164

Możesz komponować Enumerable#reducei Hash#mergeosiągać to, co chcesz.

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

Zmniejszenie tablicy w rodzaju umieszczania wywołania metody między każdym jej elementem.

Na przykład [1, 2, 3].reduce(0, :+)jest jak mówienie 0 + 1 + 2 + 3i dawanie 6.

W naszym przypadku robimy coś podobnego, ale z funkcją merge, która łączy dwa skróty.

[{: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
źródło
1
Dzięki, to świetna odpowiedź :) Bardzo ładnie wyjaśnione!
Bart Platak
42
input.reduce (&: merge) jest wystarczające.
redgetan
@redgetan czy to różni się od input.reduce(:merge)?
David van Geest
1
@David van Geest: W tym przypadku są one równoważne. Zastosowany tutaj jednoargumentowy znak ampersand tworzy blok z symbolu. Jednak redukuj ma specjalny przypadek, który akceptuje symbol. Chciałem uniknąć jednoargumentowego operatora ampersand, aby uprościć przykład, ale redgetan ma rację, że wartość początkowa jest opcjonalna w tym przypadku.
cjhveal
1
Zauważ, że jeśli użyjesz merge!zamiast mergetego, zmodyfikuje pierwszy hash (którego możesz nie chcieć), ale nie utworzy pośredniego skrótu dla każdego nowego scalania.
Phrogz
51

Co powiesz na:

h = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
r = h.inject(:merge)
shigeya
źródło
Ten schemat jest w rzeczywistości taki sam jak ten, na który odpowiedział Joshua, ale wielokrotne stosowanie #merge (nazwa metody przekazywana jako symbol) do wszystkich skrótów (pomyśl o wstrzyknięciu jako wstrzyknięciu operatora między elementami). Zobacz #inject .
shigeya
2
Dlaczego nie potrzebujemy znaku ampersand, jak w h.inject (&: merge)?
Donato
5
Ponieważ metoda inject akceptuje symbol jako parametr, który ma być interpretowany jako nazwa metody. To funkcja wstrzykiwania.
shigeya
9

Użyj #inject

hashes = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
merged = hashes.inject({}) { |aggregate, hash| aggregate.merge hash }
merged # => {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
Joshua Cheek
źródło
0

Tutaj można użyć inject lub zmniejszenia od przeliczalny klasy jak oboje są aliasy siebie więc nie ma korzyści wydajność albo.

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

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

 result2 = sample.inject(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
Nikhil Mohadikar
źródło