Rails memetakan array hash ke dalam satu hash


94

Saya memiliki serangkaian hash seperti ini:

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

Dan saya mencoba memetakan ini ke dalam satu hash seperti ini:

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

Saya telah mencapainya dengan menggunakan

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

Tapi saya bertanya-tanya apakah mungkin melakukan ini dengan cara yang lebih idiomatis (sebaiknya tanpa menggunakan variabel lokal).

Bagaimana saya bisa melakukan ini?

Jawaban:


164

Anda dapat membuat Enumerable#reducedan Hash#mergemencapai apa yang Anda inginkan.

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

Mengurangi semacam array seperti menempelkan panggilan metode di antara setiap elemennya.

Misalnya [1, 2, 3].reduce(0, :+)seperti mengatakan 0 + 1 + 2 + 3dan memberi 6.

Dalam kasus kami, kami melakukan sesuatu yang serupa, tetapi dengan fungsi penggabungan, yang menggabungkan dua hash.

[{: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
Terima kasih, ini jawaban yang bagus :) Dijelaskan dengan sangat baik!
Bart Platak

42
input.reduce (&: merge) sudah cukup.
redgetan

@redgetan apakah itu berbeda dari input.reduce(:merge)?
David van Geest

1
@David van Geest: Dalam hal ini mereka setara. Unary ampersand seperti yang digunakan di sini membentuk blok dari simbol. Namun, reduksi memiliki kasus khusus yang menerima simbol. Saya ingin menghindari operator ampersand unary untuk menyederhanakan contoh, tetapi redgetan benar bahwa nilai awal adalah opsional dalam kasus ini.
cjhveal

1
Perhatikan bahwa jika Anda menggunakan, merge!bukan mergeitu akan mengubah hash pertama (yang mungkin tidak Anda inginkan) tetapi tidak akan membuat hash perantara untuk setiap penggabungan baru.
Phrogz

51

Bagaimana tentang:

h = [{"testPARAM1"=>"testVAL1"}, {"testPARAM2"=>"testVAL2"}]
r = h.inject(:merge)

Skema ini secara efektif sama dengan apa yang dijawab Joshua, tetapi berulang kali menerapkan #merge (nama metode diteruskan sebagai simbol) pada semua hash (anggap inject sebagai menyuntikkan operator antar item). Lihat #inject .
shigeya

2
Kenapa kita tidak membutuhkan ampersand, seperti di h.inject (&: merge)?
Donato

5
Karena metode inject menerima simbol sebagai parameter untuk diinterpretasikan sebagai nama metode juga. Ini fitur suntik.
shigeya

9

Gunakan #inject

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

0

Di sini Anda dapat menggunakan injeksi atau pengurangan dari kelas Enumerable karena keduanya adalah alias satu sama lain sehingga tidak ada manfaat kinerja untuk keduanya.

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

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

 result2 = sample.inject(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.