web-dev-qa-db-fra.com

Quelle est la "manière Ruby" d'itérer sur deux tableaux à la fois

Plus d'une curiosité syntaxique qu'un problème à résoudre ...

J'ai deux tableaux de longueur égale et je veux les parcourir tous les deux en même temps, par exemple pour afficher leurs valeurs à un certain index.

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

Je sais que je peux utiliser each_index et indexe dans les tableaux comme suit:

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

Y a-t-il un façon Ruby pour le faire mieux? Quelque chose comme ça?

# 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
120
nfm
>> @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]]
260
John La Rooy

Utilisez le Array.Zip et transmettez-lui un bloc pour parcourir successivement les éléments correspondants.

21
Anurag

Il existe un autre moyen d'itérer simultanément sur deux tableaux à l'aide d'énumérateurs:

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

Les énumérateurs sont plus puissants que les exemples utilisés ci-dessus, car ils autorisent des séries infinies, une itération parallèle, entre autres techniques.

20
Donato

En plus de a.Zip(b).each{|x,y| } comme d'autres l'ont déjà dit, vous pouvez également dire [a,b].transpose.each{|x,y| }, ce qui me semble un peu plus symétrique. Probablement pas aussi vite, cependant, puisque vous créez le supplément [a,b] tableau.

16
Paul A Jungwirth

Relatif à la question initiale, pour parcourir plusieurs tableaux de inégale longueur où vous souhaitez que les valeurs circulent, vous pouvez les utiliser

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

et Ruby vous donnera

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

Cela vous évite les valeurs nil que vous obtiendrez en utilisant simplement Zip

14
xavriley

Simplement zipper les deux tableaux ensemble fonctionne bien si vous avez affaire à des tableaux. Mais que se passe-t-il si vous avez affaire à des énumérateurs sans fin, comme par exemple:

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

enum1.Zip(enum2) échoue car Zip essaie d'évaluer tous les éléments et de les combiner. Au lieu de cela, faites ceci:

enum1.lazy.Zip(enum2)

Celui-ci lazy vous enregistre en rendant l’énumérateur résultant paresseux-évaluer.

6
Justin

Pourquoi ne pas compromettre et utiliser #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] }
2
Robert Schaaf