Tại sao là each
vòng lặp ưu tiên hơn vòng lặp for
trong Ruby? Có sự khác biệt về độ phức tạp thời gian hay chúng chỉ khác nhau về cú pháp?Cách ưa thích để lặp trong Ruby là gì?
Trả lời
Một câu hỏi thú vị. Có một số cách lặp trong Ruby. Tôi đã lưu ý rằng có một nguyên tắc thiết kế trong Ruby, rằng khi có nhiều cách làm giống nhau, thường có những khác biệt tinh tế giữa chúng, và mỗi trường hợp đều có cách sử dụng riêng của nó, vấn đề riêng của nó mà nó giải quyết. Vì vậy, cuối cùng bạn cần phải có khả năng viết (và không chỉ để đọc) tất cả chúng.
Đối với câu hỏi về vòng lặp for
, điều này tương tự như my earlier question whethe for loop is a trap.
Về cơ bản có 2 cách rõ ràng chính của vòng lặp, một là bởi lặp (hay tổng quát hơn, khối), chẳng hạn như
[1, 2, 3].each { |e| puts e * 10 }
[1, 2, 3].map { |e| e * 10)
# etc., see Array and Enumerable documentation for more iterator methods.
Kết nối với cách này của iterating là lớp Enumerator
, mà bạn nên cố gắng hiểu.
Cách khác là lặp Pascal-ish theo while
, until
và for
vòng lặp.
for y in [1, 2, 3]
puts y
end
x = 0
while x < 3
puts x; x += 1
end
# same for until loop
Giống như if
và unless
, while
và until
có dạng đuôi của họ, chẳng hạn như
a = 'alligator'
a.chop! until a.chars.last == 'g'
#=> 'allig'
Thứ ba cách rất quan trọng của vòng lặp là vòng lặp ngầm, hoặc vòng lặp bằng đệ quy. Ruby là cực kỳ dễ uốn, tất cả các lớp đều có thể sửa đổi được, các móc có thể được thiết lập cho các sự kiện khác nhau, và điều này có thể được khai thác để tạo ra các cách lặp lạ thường nhất. Các khả năng rất bất tận đến mức tôi thậm chí không biết bắt đầu nói về chúng ở đâu. Có lẽ một nơi tốt là blog by Yusuke Endoh, một nghệ sĩ nổi tiếng làm việc với mã Ruby là tài liệu nghệ thuật của ông về sự lựa chọn.
Để chứng minh những gì tôi muốn nói, hãy xem xét vòng lặp này
class Object
def method_missing sym
s = sym.to_s
if s.chars.last == 'g' then s else eval s.chop end
end
end
alligator
#=> "allig"
Bên cạnh các vấn đề dễ đọc, các for
lặp loop trong Ruby đất trong khi each
làm nó từ mã nguồn gốc, vì vậy về nguyên tắc each
nên hiệu quả hơn khi lặp lại tất cả các phần tử trong một mảng.
Vòng với nhau:
arr.each {|x| puts x}
Vòng với cho:
for i in 0..arr.length
puts arr[i]
end
Trong trường hợp each
chúng tôi chỉ đi qua một khối mã đến một phương pháp thực hiện trong mã nguồn gốc của máy (mã nhanh) , trong khi trong trường hợp for
, tất cả các mã phải được hiểu và chạy có tính đến tất cả sự phức tạp của ngôn ngữ Ruby.
Tuy nhiên for
linh hoạt hơn và cho phép bạn lặp lại theo nhiều cách phức tạp hơn each
, ví dụ: lặp lại với một bước nhất định.
EDIT
Tôi không đi qua đó bạn có thể bước qua một loạt bằng cách sử dụng phương pháp bước() trước khi gọi mỗi(), do đó sự linh hoạt Tôi tuyên bố cho for
vòng lặp thực sự là phi lý.
Bạn có thể đưa ra ví dụ về một vòng lặp phức tạp trong đó 'for' phù hợp hơn' mỗi'? – Stefan
Vâng, tôi đã nghĩ rằng thực sự bước có thể được thực hiện bằng cách sử dụng phương thức step() và sau đó gọi mỗi(). Trong trường hợp này 'for' vẫn là một cách khủng khiếp để lặp: D – Claudix
BTW, vòng lặp' for' tương đương sẽ là 'cho x trong arr; đặt x; end' – Stefan
each
là cách của Ruby. Thực hiện các Iterator Pattern đã tách lợi ích.
Kiểm tra cũng này: "for" vs "each" in Ruby
Biến tham khảo một mục trong lần lặp là tạm thời và không có ý nghĩa bên ngoài của phiên. Nó là tốt hơn nếu nó được ẩn từ bên ngoài của iteration. Với các vòng lặp bên ngoài, biến đó nằm bên ngoài khối lặp. Trong các trường hợp sau,
e
chỉ hữu ích trong phạm vido
...end
, nhưng được ngăn cách với khối và được viết bên ngoài khối đó; nó không dễ dàng với một lập trình viên:for e in [:foo, :bar] do ... end
Với biến lặp nội bộ, biến khối được xác định ngay bên trong khối, nơi nó được sử dụng. Dễ đọc hơn:
[:foo, :bar].each do |e| ... end
Sự cố hiển thị này không chỉ dành cho lập trình viên. đối với tầm nhìn theo nghĩa của phạm vi với, biến cho một iterator bên ngoài là bên ngoài truy cập của lặp:
for e in [:foo] do; end e # => :foo
trong khi ở iterator nội bộ, một biến khối là vô hình từ bên ngoài:
[:foo].each do |e|; end e # => undefined local variable or method `e'
Sau này là tốt hơn từ quan điểm của đóng gói.
Khi bạn muốn tổ các vòng, thứ tự của các biến sẽ hơi ngược với vòng lặp bên ngoài:
for a in [[:foo, :bar]] do for e in a do ... end end
nhưng với lặp nội bộ, trật tự là đơn giản hơn:
[[:foo, :bar]].each do |a| a.each do |e| ... end end
Với các trình vòng lặp bên ngoài, bạn chỉ có thể sử dụng cú pháp Ruby mã hóa cứng, và bạn cũng phải nhớ kết hợp giữa từ khóa và phương thức được gọi nội bộ (
for
gọieach
), nhưng đối với các trình vòng lặp nội bộ, bạn có thể định nghĩa của riêng bạn, cho phép sự linh hoạt.
Có, đây là hai cách lặp lại khác nhau, Nhưng hy vọng tính toán này sẽ giúp.
require 'benchmark'
a = Array(1..100000000)
sum = 0
Benchmark.realtime {
a.each { |x| sum += x }
}
này có 5,866932 giây
a = Array(1..100000000)
sum = 0
Benchmark.realtime {
for x in a
sum += x
end
}
này có 6,146521 giây.
Mặc dù đây không phải là cách đúng để thực hiện điểm chuẩn, cũng có một số ràng buộc khác.Nhưng trên một máy duy nhất, mỗi máy dường như nhanh hơn một chút.
+1 để minh họa 'Điểm chuẩn'. –
Bạn có chắc chắn rằng các điểm chuẩn đó có âm thanh thống kê không? Vì 'for' desugars to' each', tôi không mong đợi có sự khác biệt. Nếu có, 'for' sẽ nhanh hơn một chút vì nó không cần phân bổ một phạm vi cục bộ mới vì các biến được khai báo bên trong một vòng lặp' for' gây ô nhiễm phạm vi bên ngoài, trong khi khối được truyền tới 'mỗi' có phạm vi riêng của nó . –
@ JörgWMittag, cái gì? Có 'for' thực sự desugar để' mỗi'? Và, btw., Tôi cũng hy vọng 'for' sẽ nhanh hơn một chút vì cùng một lý do. Tôi giải thích sự quan sát ngược lại với các nhà phát triển Ruby chú ý nhiều hơn đến việc tối ưu hóa 'mỗi' hơn' for'. –
- 1. Cách ưa thích để preallocate mảng NumPy là gì?
- 2. cách ưa thích để triển khai hashCode() là gì?
- 3. Cách ưa thích của chuỗi chức năng Underscore.js là gì?
- 4. Cách ưa thích để thực hiện cài đặt trong ứng dụng Ruby on Rails 3 là gì?
- 5. Cách ưa thích để thụt lề các trường hợp trong một công tắc là gì?
- 6. Cách ưa thích để quản lý đơn đặt hàng trong mẫu trình xây dựng là gì?
- 7. Cách nhanh nhất/ưa thích để lưu trữ dữ liệu tĩnh trong Android là gì?
- 8. Cách ưa thích để trả về một bảng trống trong SQL là gì?
- 9. Cách ưa thích để tránh tiêm SQL trong Spark-SQL (trên Hive) là gì
- 10. Cách ưa thích để trả về phản hồi JSON trống trong Rails 3 là gì?
- 11. Phần mở rộng tệp Pascal ưa thích là gì?
- 12. Thư viện mẫu ưa thích cho jQuery là gì?
- 13. Cách ưa thích của dữ liệu tải lười cho ng-include trong Angular là gì?
- 14. Cách ưa thích để sử dụng favicon?
- 15. Cách ưa thích để làm mẫu trang web và chủ đề với Wicket là gì?
- 16. Cách ưa thích để đổ một đối tượng JSON là gì? to_json, JSON.generate hoặc JSON.dump?
- 17. Cách ưa thích để kết hợp hai bồn rửa là gì?
- 18. Cách ưa thích để kết nối với cơ sở dữ liệu postgresql từ PHP là gì?
- 19. Cách ưa thích để thoát khỏi chương trình dòng lệnh là gì?
- 20. Cách ưa thích của bạn trong việc thử nghiệm đoạn mã javascript là gì?
- 21. Phong cách ưa thích của bạn cho các biến đặt tên trong R là gì?
- 22. Phương pháp ưa thích để in bằng máy in trong VB.NET là gì?
- 23. Cách ưa thích của bạn đối phó với phát triển đa nền tảng là gì?
- 24. Cách ưa thích (kiểu tốt hơn) để đặt tên cho một không gian tên trong Ruby là gì? Số ít hoặc số nhiều?
- 25. Cách ưa thích để có được đường dẫn máy chủ đầy đủ trong chế độ xem ASP.NET MVC là gì?
- 26. Cách ưa thích để bao gồm các nguồn QML trong bản dựng ứng dụng của bạn là gì?
- 27. cách ưa thích để thực hiện xác thực người dùng và ủy quyền trong Clojure là gì?
- 28. Phương pháp ưa thích cho TCP/IP IPC trong Python không gấp bội là gì?
- 29. Cách thích hợp để truy cập các biến lớp trong Ruby 1.9 là gì?
- 30. Cách thích hợp để xử lý miền địa lý trong Ruby on Rails là gì?
Điều này sẽ bị đóng dưới dạng trùng lặp chứ không phải dựa trên ý kiến. Câu thứ hai đưa ra một tiêu chí rõ ràng cho những gì "ưa thích" trong câu đầu tiên có nghĩa là, IMO. Tôi chắc chắn có một bản sao ở đâu đó, mặc dù. –
Điều này không cần phải đóng cửa. SO không phải là Wikipedia. Chúng tôi có thể có hai hoặc bảy chủ đề thảo luận các câu hỏi liên quan chặt chẽ. Với tất cả các do tuyên bố rõ ràng tôn trọng tình trạng thâm niên rất cao của bạn ở đây. –