'Ruby way' คืออะไรในการวนซ้ำสองอาร์เรย์พร้อมกัน


127

ความอยากรู้อยากเห็นทางไวยากรณ์มากกว่าปัญหาในการแก้ ...

ฉันมีอาร์เรย์สองอาร์เรย์ที่มีความยาวเท่ากันและต้องการทำซ้ำทั้งสองอาร์เรย์พร้อมกันตัวอย่างเช่นเพื่อส่งออกทั้งสองค่าที่ดัชนีหนึ่ง

@budget = [ 100, 150, 25, 105 ]
@actual = [ 120, 100, 50, 100 ]

ฉันรู้ว่าฉันสามารถใช้each_indexและทำดัชนีในอาร์เรย์ได้ดังนี้:

@budget.each_index do |i|
  puts @budget[i]
  puts @actual[i]
end

มีวิธีที่ทับทิมจะทำเช่นนี้ดีขึ้นหรือไม่ อะไรทำนองนี้?

# Obviously doesn't achieve what I want it to - but is there something like this?
[@budget, @actual].each do |budget, actual|
  puts budget
  puts actual
end

1
อาร์เรย์ทั้งสองมีขนาดเท่ากันหรือไม่
Anurag

1
ใช่ - ทั้งคู่รู้ว่ามีความยาวเท่ากัน
nfm

คำตอบ:


276
>> @budget = [ 100, 150, 25, 105 ]
=> [100, 150, 25, 105]
>> @actual = [ 120, 100, 50, 100 ]
=> [120, 100, 50, 100]

>> @budget.zip @actual
=> [[100, 120], [150, 100], [25, 50], [105, 100]]

>> @budget.zip(@actual).each do |budget, actual|
?>   puts budget
>>   puts actual
>> end
100
120
150
100
25
50
105
100
=> [[100, 120], [150, 100], [25, 50], [105, 100]]

12
'.each' สามารถเปิดองค์ประกอบอาร์เรย์ได้หรือไม่? ฉันสงสัยว่าฉันไม่รู้ว่า Ruby มีอีกมากแค่ไหน: /
Nikita Rybak

5
หากคุณจะใช้นิพจน์เช่นนั้นคุณควรใช้วงเล็บสำหรับการเรียกเมธอดเสมอในกรณีนี้ @ budget.zip (@actual)
.each

1
@AboutRuby: ในกรณีนี้จำเป็น! แก้ไขแล้ว.
Marc-André Lafortune

2
เมื่อฉันเห็นเส้นทับทิมแบบนี้ฉันก็โยนมือของฉันขึ้นไปในอากาศและเดินไปรอบ ๆ ห้องเหมือนแชมป์!
iGbanam

9
ขนาดนี้? ถ้าฉันมีอาร์เรย์ 2 10,000 รายการจำเป็นต้องสร้างอาร์เรย์รายการ 20,000 รายการหรือไม่ เอกสารแนะนำสิ่งนี้
Tom Andersen


20

มีอีกวิธีหนึ่งในการวนซ้ำสองอาร์เรย์พร้อมกันโดยใช้ตัวนับ:

2.1.2 :003 > enum = [1,2,4].each
 => #<Enumerator: [1, 2, 4]:each> 
2.1.2 :004 > enum2 = [5,6,7].each
 => #<Enumerator: [5, 6, 7]:each> 
2.1.2 :005 > loop do
2.1.2 :006 >     a1,a2=enum.next,enum2.next
2.1.2 :007?>   puts "array 1 #{a1} array 2 #{a2}"
2.1.2 :008?>   end
array 1 1 array 2 5
array 1 2 array 2 6
array 1 4 array 2 7

ตัวแจงนับมีประสิทธิภาพมากกว่าตัวอย่างที่ใช้ข้างต้นเนื่องจากอนุญาตให้ใช้อนุกรมที่ไม่สิ้นสุดการวนซ้ำแบบขนานและเทคนิคอื่น ๆ


1
มีวิธีรับดัชนีภายในที่loopแสดงด้านบนหรือไม่?
Biju

16

นอกเหนือจากa.zip(b).each{|x,y| }ที่คนอื่นพูดแล้วคุณยังสามารถพูด[a,b].transpose.each{|x,y| }ได้ซึ่งทำให้ฉันรู้สึกสมมาตรขึ้นเล็กน้อย อาจจะไม่เร็วเท่าไหร่เนื่องจากคุณกำลังสร้าง[a,b]อาร์เรย์พิเศษ


11
+1 สิ่งที่ดีอย่างหนึ่งtransposeคือมีข้อยกเว้นหากอาร์เรย์ทั้งสองมีความยาวไม่เท่ากัน
Andrew Grimm

14

ที่เกี่ยวข้องกับคำถามเดิมสำหรับการวนซ้ำอาร์เรย์ที่มีความยาวไม่เท่ากันซึ่งคุณต้องการให้ค่าวนรอบคุณสามารถใช้ได้

[1,2,3,4,5,6].zip([7,8,9].cycle)

และทับทิมจะให้คุณ

[[1, 7], [2, 8], [3, 9], [4, 7], [5, 8], [6, 9]]

วิธีนี้ช่วยให้คุณประหยัดnilค่าที่คุณจะได้รับจากการใช้ zip


6

การบีบอัดอาร์เรย์ทั้งสองเข้าด้วยกันจะทำงานได้ดีหากคุณกำลังจัดการกับอาร์เรย์ แต่จะเกิดอะไรขึ้นถ้าคุณกำลังจัดการกับตัวนับที่ไม่มีวันสิ้นสุดเช่นสิ่งเหล่านี้:

enum1 = (1..5).cycle
enum2 = (10..12).cycle

enum1.zip(enum2)ล้มเหลวเนื่องจากzipพยายามประเมินองค์ประกอบทั้งหมดและรวมเข้าด้วยกัน ให้ทำสิ่งนี้แทน:

enum1.lazy.zip(enum2)

สิ่งนั้นlazyช่วยคุณประหยัดโดยการทำให้ตัวแจงนับผลลัพธ์ขี้เกียจประเมิน


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.