2つの配列を一度に反復する「Rubyの方法」とは


127

解決すべき問題よりも構文の好奇心のほうが...

同じ長さの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の方法はありますか?このような何か?

# 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
両方の配列は同じサイズですか?
Anurag 2010

1
うん-どちらも同じ長さであることが知られている
nfm 2010

回答:


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'は配列要素を展開できますか?Rubyのどれだけ分からないのか知りません:/
Nikita Rybak

5
このような式を使用する場合は、念のため、メソッドの呼び出しには常に括弧を使用するのが最善です。@ budget.zip(@actual).each
AboutRuby

1
@AboutRuby:この場合、それは必要です!修繕。
マルク=アンドレ・Lafortune

2
このようなルビーのラインを見ると、手を空中に投げ、部屋の周りをチャンピオンのように歩き回ります!
iGbanam 2012年

9
これはスケールしますか?2 10000アイテムの配列がある場合、20,000アイテムの配列を作成する必要がありますか?ドキュメントはこれを示唆しています。
トムアンデルセン


20

列挙子を使用して一度に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

列挙子は、他の手法の中でも特に、無限直列、並列反復を可能にするため、上記で使用した例よりも強力です。


1
loop上記の内部にインデックスを取得する方法はありますか?
Biju 2018

16

加えて、a.zip(b).each{|x,y| }他の人が言ってきたように、あなたも言うことができる[a,b].transpose.each{|x,y| }ほんの少しより対称として私を打つています、。ただし、追加の[a,b]配列を作成しているため、おそらくそれほど速くありません。


11
+1優れている点の1つは、transpose2つの配列の長さが同じでない場合に例外が発生することです。
Andrew Grimm

14

元の質問に関連して、値を循環させたい長さが等しくない配列を反復するために使用できます

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

そしてルビーはあなたに与えるでしょう

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

これにより、nilzipを使用するだけで得られる値を節約できます。


6

配列を扱う場合は、2つの配列を圧縮するだけで十分です。しかし、次のような無限の列挙子を扱っている場合はどうでしょう。

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

enum1.zip(enum2)zipすべての要素を評価し、それらを結合しようとするため、失敗します。代わりに、次のようにします。

enum1.lazy.zip(enum2)

そのlazy結果、列挙子を遅延評価することで節約できます。


2

妥協して#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] }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.