'Cách Ruby' để lặp lại qua hai mảng cùng một lúc


127

Nhiều sự tò mò về cú pháp hơn là một vấn đề cần giải quyết ...

Tôi có hai mảng có độ dài bằng nhau và muốn lặp lại cả hai 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_indexvà lập chỉ mục vào các mảng như vậy:

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

cách nào để làm điều này tốt hơn không? Một cái gì đó như thế 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
cả hai mảng có kích thước bằng nhau?
Anurag

1
Đúng - cả hai đều có cùng độ dài
nfm

Câu trả lời:


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

5
Nếu bạn sẽ sử dụng một biểu thức như vậy, 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. @ ngân sách.zip (@actual) .each
AboutRuby

1
@ AboutRuby: Trong trường hợp này, nó là cần thiết! Đã sửa.
Marc-André Lafortune

2
Khi tôi nhìn thấy những dòng ruby ​​như thế này, tôi giơ tay lên không trung và vòng quanh phòng như một nhà vô địch!
iGbanam

9
Liệu quy mô này? Nếu tôi có 2 10000 mảng mảng thì điều này có yêu cầu tạo một mảng 20.000 mặt hàng không? Các tài liệu đề nghị này.
Tom Andersen

21

Sử dụng Array.zipphương thức và truyền cho nó một khối để lặp lại các phần tử tương ứng một cách tuần tự.


20

Có một cách khác để lặp lại hai mảng cùng một lúc bằng cách sử dụng liệt kê:

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 liệt kê mạnh hơn các ví dụ được sử dụng ở trên, vì chúng cho phép chuỗi vô hạn, lặp song song, trong số các kỹ thuật khác.


1
Có cách nào để có được chỉ số bên trong loophiển thị ở trên?
biju

16

Ngoài a.zip(b).each{|x,y| }những gì người khác đã nói, bạn cũng có thể nói [a,b].transpose.each{|x,y| }, điều này gây ấn tượng với tôi như một chút đối xứng hơn. Tuy nhiên, có lẽ không nhanh như vậy vì bạn đang tạo [a,b]mảng bổ sung .


11
+1 Một trong những điều hay ho transposelà nó làm tăng ngoại lệ nếu hai mảng không có cùng độ dài.
Andrew Grimm

14

Liên quan đến câu hỏi ban đầu, để lặp lại các mảng có độ dài không bằng nhau , nơi bạn muốn các giá trị xoay quanh bạn có thể sử dụng

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

và Ruby sẽ cho bạn

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

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


6

Đơn giản chỉ cần nén hai mảng lại với nhau sẽ hoạt động tốt nếu bạn đang xử lý các mảng. Nhưng điều gì sẽ xảy ra nếu bạn đang đối phó với các điều tra viên không bao giờ kết thúc, chẳng hạn như một cái gì đó như sau:

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

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

enum1.lazy.zip(enum2)

Điều đó lazygiúp bạn tiết kiệm bằng cách làm cho điều tra viên kết quả lười biếng đánh giá.


2

Làm thế nào về việc 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] }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.