解決する問題よりも構文の好奇心の方が多い...
同じ長さの2つの配列があり、一度に両方を反復処理したい-たとえば、特定のインデックスで両方の値を出力したい場合。
@budget = [ 100, 150, 25, 105 ]
@actual = [ 120, 100, 50, 100 ]
each_index
を使用して、次のように配列にインデックスを付けることができることを知っています。
@budget.each_index do |i|
puts @budget[i]
puts @actual[i]
end
Ruby wayはこれをより良くするためにありますか?何かlike this?
# 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]]
使用 - Array.Zip
メソッド。ブロックを渡して、対応する要素を順番に繰り返し処理します。
列挙子を使用して、2つの配列を一度に繰り返す別の方法があります。
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
列挙子は、他の手法の中でも特に、無限級数、並列反復を可能にするため、上記で使用した例よりも強力です。
他の人が言ったa.Zip(b).each{|x,y| }
に加えて、[a,b].transpose.each{|x,y| }
と言うこともできます。ただし、余分な[a,b]
配列を作成しているため、おそらくそれほど高速ではありません。
元の質問に関連して、値を循環させたい不等長さの配列を反復処理するために使用できます
[1,2,3,4,5,6].Zip([7,8,9].cycle)
およびRubyは
[[1, 7], [2, 8], [3, 9], [4, 7], [5, 8], [6, 9]]
これにより、Zipを使用するだけで得られるnil
値を節約できます。
配列を扱う場合は、2つの配列を単純に圧縮するだけで十分に機能します。しかし、次のような終わらない列挙子を扱っている場合はどうでしょうか。
_enum1 = (1..5).cycle
enum2 = (10..12).cycle
_
Zip
はすべての要素を評価して結合しようとするため、enum1.Zip(enum2)
は失敗します。代わりに、これを行います:
_enum1.lazy.Zip(enum2)
_
そのlazy
は、結果の列挙子を遅延評価することであなたを救います。
妥協し、#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] }