2010-08-26 36 views
105

Thêm sự tò mò về cú pháp hơn là một vấn đề cần giải quyết ...Cách 'Ruby' để lặp qua hai mảng cùng một lúc

Tôi có hai mảng có độ dài bằng nhau và muốn lặp lại chúng cùng một lúc - ví dụ, để xuất cả hai giá trị của chúng tại một chỉ mục nhất định.

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

tôi biết rằng tôi có thể sử dụng each_index và chỉ số vào mảng như vậy:

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

của Ruby cách để làm điều này tốt hơn? Một cái gì đó như điều này?

# 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

là cả hai mảng có kích thước bằng nhau không? – Anurag

+1

Đúng - cả hai được biết là có cùng độ dài – nfm

Trả lời

241
>> @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' có thể mở ra các phần tử mảng? Tôi tự hỏi tôi không biết Ruby nhiều hơn bao nhiêu:/ –

+1

Tôi yêu Ruby!:) – nfm

+5

Nếu bạn định sử dụng một biểu thức như vậy, cách tốt nhất là sử dụng dấu ngoặc đơn cho các cuộc gọi phương thức, chỉ trong trường hợp. @ budget.zip (@actual) .each – AboutRuby

21

Sử dụng phương pháp Array.zip và chuyển cho nó một khối để lặp qua các phần tử tương ứng theo tuần tự.

+0

hoàn hảo, dễ dàng và hiệu quả – akostadinov

16

Ngoài a.zip(b).each{|x,y| } như những người khác đã nói, bạn cũng có thể nói [a,b].transpose.each{|x,y| }, mà đập vào mắt tôi như đối xứng hơn một chút. Có lẽ không phải là nhanh, mặc dù, kể từ khi bạn đang tạo thêm [a,b] mảng.

+11

+1 Một trong những điều tốt đẹp về 'transpose' là nó làm tăng ngoại lệ nếu hai mảng không cùng độ dài. –

18

Có một cách khác để lặp qua hai mảng cùng một lúc sử dụng điều tra viên:

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 

Các điều tra viên đang mạnh hơn các ví dụ sử dụng ở trên, bởi vì chúng cho phép chuỗi vô hạn, lặp song song, trong số các kỹ thuật khác.

13

liên quan đến câu hỏi ban đầu, cho iterating trên mảng của bất bình đẳng chiều dài nơi bạn muốn các giá trị để chu kỳ xung quanh bạn có thể sử dụng

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

và Ruby sẽ cung cấp cho bạn

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

này giúp bạn tiết kiệm từ các giá trị nil mà bạn sẽ nhận được từ việc chỉ sử dụng zip

+1

Tidbit đẹp của Ruby. – alistairholt

+1

đây là những gì tôi đang tìm kiếm, cảm ơn bạn! – Malachi

5

Chỉ cần nén hai giá trị đó mảng với nhau hoạt động tốt nếu bạn đang xử lý mảng. Nhưng nếu bạn đang đối phó với điều tra viên không có điểm dừng, chẳng hạn như một cái gì đó như thế này:

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

enum1.zip(enum2) thất bại vì zip cố gắng để đánh giá tất cả các yếu tố và kết hợp chúng. Thay vào đó, hãy thực hiện điều này:

enum1.lazy.zip(enum2) 

Điều đó một lazy giúp bạn tiết kiệm bằng cách thực hiện kết quả đánh giá lười.

1

Làm cách nào để thỏa hiệp và sử dụng #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] } 
Các vấn đề liên quan