Rails แมปอาร์เรย์ของแฮชลงในแฮชเดียว


94

ฉันมีแฮชมากมายดังนี้:

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

และฉันกำลังพยายามแมปสิ่งนี้กับแฮชเดียวดังนี้:

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

ฉันประสบความสำเร็จโดยใช้

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

แต่ฉันสงสัยว่าเป็นไปได้ไหมที่จะทำในลักษณะที่เป็นสำนวนมากกว่านี้ (ควรจะไม่ใช้ตัวแปรท้องถิ่น)

ฉันจะทำเช่นนี้ได้อย่างไร?

คำตอบ:


164

คุณสามารถเขียนEnumerable#reduceและHash#mergeทำสิ่งที่คุณต้องการให้สำเร็จได้

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

การลดการเรียงลำดับอาร์เรย์เช่นการติดการเรียกเมธอดระหว่างแต่ละองค์ประกอบของมัน

ยกตัวอย่างเช่น[1, 2, 3].reduce(0, :+)เป็นเหมือนว่าและให้0 + 1 + 2 + 36

ในกรณีของเราเราทำสิ่งที่คล้ายกัน แต่ด้วยฟังก์ชันการผสานซึ่งรวมสองแฮช

[{: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
ขอบคุณนี่คือคำตอบที่ดี :) อธิบายได้ดีมาก!
Bart Platak

42
input.reduce (&: merge) ก็เพียงพอแล้ว
redgetan

@redgetan แตกต่างจากinput.reduce(:merge)อะไร?
David van Geest

1
@David van Geest: ในกรณีนี้เทียบเท่ากัน เครื่องหมายยูนารีตามที่ใช้ในที่นี้จะสร้างบล็อกจากสัญลักษณ์ อย่างไรก็ตามการลดมีกรณีพิเศษที่ยอมรับสัญลักษณ์ ฉันต้องการหลีกเลี่ยงตัวดำเนินการเครื่องหมายแอมเพอร์แซนด์ที่ไม่ได้เรียนรู้เพื่อทำให้ตัวอย่างง่ายขึ้น แต่การกำหนดค่าใหม่ถูกต้องว่าค่าเริ่มต้นเป็นทางเลือกในกรณีนี้
cjhveal

1
โปรดทราบว่าหากคุณใช้merge!แทนmergeมันจะแก้ไขแฮชแรก (ซึ่งคุณอาจไม่ต้องการ) แต่จะไม่สร้างแฮชตัวกลางสำหรับการผสานใหม่แต่ละครั้ง
Phrogz

51

เกี่ยวกับ:

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

โครงร่างนี้มีประสิทธิภาพเหมือนกับสิ่งที่ Joshua ตอบ แต่ใช้ #merge ซ้ำ ๆ (ชื่อเมธอดที่ส่งผ่านเป็นสัญลักษณ์) กับแฮชทั้งหมด (คิดว่าการฉีดเป็นการฉีดตัวดำเนินการระหว่างรายการ) อ้างถึง#inject
shigeya

2
ทำไมเราไม่ต้องการเครื่องหมายแอมเพอร์แซนด์เหมือนใน h.inject (&: merge)?
Donato

5
เนื่องจากวิธีการฉีดยอมรับสัญลักษณ์เป็นพารามิเตอร์ที่จะตีความเป็นชื่อเมธอดด้วย เป็นคุณสมบัติของการฉีด
shigeya


0

ที่นี่คุณสามารถใช้การแทรกหรือลดจากคลาสEnumerableเนื่องจากทั้งสองเป็นนามแฝงของกันและกันดังนั้นจึงไม่มีประโยชน์ด้านประสิทธิภาพเช่นกัน

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

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

 result2 = sample.inject(:merge)
 # {"testPARAM1"=>"testVAL1", "testPARAM2"=>"testVAL2"}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.