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.