Apa itu 'Cara Ruby' untuk mengulang dua array sekaligus

127

Lebih dari keingintahuan sintaksis daripada masalah untuk dipecahkan ...

Saya memiliki dua array dengan panjang yang sama, dan ingin mengulangi keduanya sekaligus - misalnya, untuk menampilkan kedua nilai mereka pada indeks tertentu.

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

Saya tahu bahwa saya dapat menggunakan each_indexdan mengindeks ke dalam array seperti:

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

Apakah ada cara Ruby untuk melakukan ini lebih baik? Sesuatu seperti ini?

# 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
nfm
sumber
1
keduanya adalah array dengan ukuran yang sama?
Anurag
1
Yap - keduanya diketahui memiliki panjang yang sama
nfm

Jawaban:

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]]
John La Rooy
sumber
12
'.each' dapat membuka elemen array? Saya ingin tahu berapa banyak lagi dari Ruby yang saya tidak tahu: /
Nikita Rybak
5
Jika Anda akan menggunakan ekspresi seperti itu, selalu terbaik untuk menggunakan tanda kurung untuk panggilan metode, untuk berjaga-jaga. @ budget.zip (@actual) .each
AboutRuby
1
@AboutRuby: Dalam hal ini, diperlukan! Tetap.
Marc-André Lafortune
2
ketika saya melihat garis ruby ​​seperti ini, saya melemparkan tangan saya di udara dan wal mengelilingi ruangan seperti juara!
iGbanam
9
Apakah skala ini? Jika saya memiliki 2 10.000 item array apakah ini mengharuskan membuat 20.000 item array? Dokumen menyarankan ini.
Tom Andersen
21

Gunakan Array.zipmetode ini dan berikan blok untuk beralih pada elemen yang sesuai secara berurutan.

Anurag
sumber
20

Ada cara lain untuk beralih dua array sekaligus menggunakan enumerator:

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

Pencacah lebih kuat daripada contoh yang digunakan di atas, karena mereka memungkinkan deret tak terbatas, iterasi paralel, di antara teknik lainnya.

Donato
sumber
1
Apakah ada cara untuk mendapatkan indeks di dalam yang loopditunjukkan di atas?
Biju
16

Selain a.zip(b).each{|x,y| }seperti yang dikatakan orang lain, Anda juga bisa mengatakan [a,b].transpose.each{|x,y| }, yang menurut saya sedikit lebih simetris. Namun, mungkin tidak secepat karena Anda membuat [a,b]array ekstra .

Paul A Jungwirth
sumber
11
+1 Salah satu hal yang menyenangkan tentang transposeitu menimbulkan pengecualian jika kedua array tidak sama panjang.
Andrew Grimm
14

Terkait dengan pertanyaan awal, untuk mengulangi susunan dengan panjang yang tidak sama di mana Anda ingin nilai-nilai berputar di sekitar Anda dapat menggunakan

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

dan Ruby akan memberimu

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

Ini menyelamatkan Anda dari nilnilai - nilai yang akan Anda dapatkan dari hanya menggunakan zip

xavriley
sumber
6

Cukup dengan zip kedua array bekerja dengan baik jika Anda berurusan dengan array. Tetapi bagaimana jika Anda berhadapan dengan pencacah yang tidak pernah berakhir, seperti sesuatu seperti ini:

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

enum1.zip(enum2)gagal karena zipmencoba untuk mengevaluasi semua elemen dan menggabungkannya. Sebaliknya, lakukan ini:

enum1.lazy.zip(enum2)

Yang itu lazymenyelamatkan Anda dengan membuat enumerator yang dihasilkan malas mengevaluasi.

Justin
sumber
2

Bagaimana dengan berkompromi, dan menggunakan #each_with_index?

include Enumerable 

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

@budget.each_with_index { |val, i| puts val; puts @actual[i] }
Robert Schaaf
sumber