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
>> @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]]
Utilisez le Array.Zip
et transmettez-lui un bloc pour parcourir successivement les éléments correspondants.
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.
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.
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
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.
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] }