Aynı anda iki diziyi yinelemenin 'Ruby yolu' nedir?


127

Çözülmesi gereken bir problemden çok sözdizimi merakı ...

Eşit uzunlukta iki dizim var ve her ikisini de aynı anda yinelemek istiyorum - örneğin, her iki değerini de belirli bir dizinde çıkarmak için.

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

each_indexDizileri şu şekilde kullanabileceğimi ve indeksleyebileceğimi biliyorum :

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

Bunu daha iyi yapmanın bir Ruby yolu var mı ? Bunun gibi bir şey mi?

# 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
dizilerin ikisi de eşit büyüklükte mi?
Anurag

1
Evet - her ikisinin de aynı uzunlukta olduğu biliniyor
nfm

Yanıtlar:


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' dizi elemanlarını açabilir mi? Acaba daha ne kadar Ruby bilmiyorum: /
Nikita Rybak

5
Böyle bir ifade kullanacaksanız, her ihtimale karşı yöntem çağrıları için parantez kullanmak her zaman en iyisidir. @ budget.zip (@gerçek) .each
AboutRuby

1
@AboutRuby: Bu durumda gerekli! Sabit.
Marc-André Lafortune

2
Böyle yakut çizgileri gördüğümde ellerimi havaya kaldırıyorum ve bir şampiyon gibi odanın etrafında dolanıyorum!
iGbanam

9
Bu ölçeklenir mi? 2 10000 maddelik dizim varsa, bu 20.000 maddelik bir dizi oluşturmayı gerektirir mi? Doktorlar bunu öneriyor.
Tom Andersen

21

Array.zipYöntemi kullanın ve karşılık gelen öğeleri sırayla yinelemek için bir blok geçirin.


20

Numaralandırıcıları kullanarak aynı anda iki diziyi yinelemenin başka bir yolu vardır:

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

Numaralandırıcılar yukarıda kullanılan örneklerden daha güçlüdür çünkü diğer tekniklerin yanı sıra sonsuz seriye, paralel yinelemeye izin verirler.


1
loopYukarıda gösterilen indeksi almanın bir yolu var mı ?
Biju

16

Ek olarak a.zip(b).each{|x,y| }diğerleri söylediler, ayrıca söyleyebiliriz [a,b].transpose.each{|x,y| }bir nebze daha simetrik olarak beni vurur ki,. Muhtemelen o kadar hızlı değil, çünkü ekstra [a,b]dizi yaratıyorsunuz .


11
+1 transposeBununla ilgili güzel şeylerden biri , iki dizinin aynı uzunlukta olmaması durumunda bir istisna yaratmasıdır.
Andrew Grimm

14

Orijinal soruyla ilgili olarak, değerlerin etrafında dönmesini istediğiniz yerde eşit olmayan uzunluktaki dizileri yinelemek için kullanabilirsiniz

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

ve Ruby sana verecek

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

Bu sizi nilsadece zip kullanarak elde edeceğiniz değerlerden kurtarır


6

Dizilerle uğraşıyorsanız, iki diziyi birlikte sıkıştırmak iyi çalışır. Ama ya hiç bitmeyen sayım görevlileri ile uğraşıyorsanız, örneğin aşağıdakiler gibi:

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

enum1.zip(enum2)başarısız olduğu zipiçin tüm öğeleri değerlendirmeye ve birleştirmeye çalışır. Bunun yerine şunu yapın:

enum1.lazy.zip(enum2)

Bu lazy, ortaya çıkan numaralandırıcıyı tembel değerlendirme yaparak kurtarır.


2

Ödün vermeye ve #each_with_index kullanmaya ne dersiniz?

include Enumerable 

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

@budget.each_with_index { |val, i| puts val; puts @actual[i] }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.