Có bất kỳ lợi ích của việc sử dụng biến phụ này trong chú thích vòng lặp for không?


11

Tôi đã tìm thấy chú thích vòng lặp sau trong một dự án lớn mà tôi đang thực hiện (mã giả):

var someOtherArray = [];
for (var i = 0, n = array.length; i < n; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

Điều khiến tôi chú ý là biến "n" thêm này. Tôi chưa bao giờ thấy một lop được viết theo cách này trước đây.

Rõ ràng trong kịch bản này, không có lý do tại sao mã này không thể được viết theo cách sau (mà tôi rất quen thuộc):

var someOtherArray = [];
for (var i = 0; i < array.length; i++) {
    someOtherArray[i] = modifyObjetFromArray(array[i]);
}

Nhưng nó làm tôi suy nghĩ.

Có một kịch bản khi viết một vòng lặp for như vậy sẽ có ý nghĩa? Ý tưởng xuất hiện rằng độ dài "mảng" có thể thay đổi trong quá trình thực hiện vòng lặp for, nhưng chúng tôi không muốn lặp xa hơn kích thước ban đầu, nhưng tôi không thể tưởng tượng được một kịch bản như vậy.

Thu hẹp mảng bên trong vòng lặp cũng không có nhiều ý nghĩa, bởi vì chúng ta có khả năng nhận được OutOfBoundException.

Có một mẫu thiết kế đã biết mà chú thích này hữu ích không?

Chỉnh sửa Như đã lưu ý bởi @ Jerry101, lý do là hiệu suất. Đây là một liên kết đến bài kiểm tra hiệu suất tôi đã tạo: http://jsperf.com/ninforloop . Theo tôi, sự khác biệt không đủ lớn trừ khi bạn lặp đi lặp lại mặc dù một mảng rất lớn. Mã tôi đã sao chép nó chỉ có tối đa 20 yếu tố, vì vậy tôi nghĩ khả năng đọc trong trường hợp này vượt trội hơn so với việc xem xét hiệu suất.


Phản ứng với bạn chỉnh sửa: đây là lập trình hướng đối tượng. Tiêu chuẩn mảng.length là nhanh và rẻ. Nhưng vì lý do gì, việc triển khai .length có thể thay đổi thành một thứ đắt tiền. Nếu một giá trị giữ nguyên thì đừng lấy nó nhiều lần.
Pieter B

Tôi đồng ý. Thật tốt khi biết về tùy chọn này, nhưng tôi có thể sẽ không sử dụng nó thường xuyên, trừ khi tôi lấy một ví dụ tương tự với truy vấn sql của bạn. Cảm ơn bạn
Vlad Spreys

Điều quan trọng là, nếu mảng của bạn là một triệu mục, bạn sẽ gọi mảng. Một triệu lần thay vì 1 lần trong khi giá trị vẫn giữ nguyên. Hỏi điều gì đó hàng triệu lần và biết rằng mỗi câu trả lời tiếp theo sẽ giống như câu trả lời đầu tiên ...... nghe có vẻ hơi vô nghĩa với tôi.
Pieter B

1
Tôi không thấy rằng điều này làm cho mã khó đọc hơn đáng kể. . cho bạn; và 2) đây có thể không phải là một điểm nóng. Có vẻ như không đáng để ai đó dành thêm 5 giây để phân tích cú pháp trừ khi nó ở trong thư viện (ví dụ: việc triển khai cấu trúc dữ liệu.)
Doval 30/1/2015

1
Trong C # /. NET, biến thể sử dụng ncó thể chậm hơn biến thể sử dụng array.Lengthdo JITter có thể không nhận thấy rằng nó có thể loại bỏ kiểm tra giới hạn mảng.
CodeInChaos

Câu trả lời:


27

Biến nđảm bảo mã được tạo không lấy chiều dài mảng cho mỗi lần lặp.

Đó là một tối ưu hóa có thể tạo ra sự khác biệt về thời gian chạy tùy thuộc vào ngôn ngữ được sử dụng, liệu mảng đó thực sự là một đối tượng tập hợp hay "mảng" JavaScript và các chi tiết tối ưu hóa khác.


3
Không, nó không. Việc độ dài của mảng có được tìm nạp mỗi lần lặp không chỉ phụ thuộc vào ngôn ngữ, mà còn phụ thuộc vào các tùy chọn trình biên dịch và trình biên dịch và những gì được thực hiện trong vòng lặp (tôi đang nói về C và C ++)
Bовић 30/1/2015

.. Và ngay cả như vậy, cá nhân tôi sẽ đặt phép gán n ngay phía trên vòng lặp nếu tôi thực sự muốn nó, vì - như OP đã lưu ý - đây là một cấu trúc (YMMV) hiếm để sử dụng và nó dễ bị bỏ qua / không hiểu bởi các nhà phát triển khác mật mã.
cwap

20
Như đã viết, nó phạm vi nvòng lặp, thường là một điều tốt. Tôi chỉ xác định nó trước vòng lặp nếu tôi muốn sử dụng lại sau.
Jerry101

4
@ Jerry101: Rõ ràng đoạn trích mẫu là JavaScript, nơi không có thứ gọi là phạm vi vòng lặp
Bergi

1
@ BЈẫy
Matteo Italia

2

Việc tìm nạp độ dài của mảng có thể dễ dàng "đắt hơn" sau đó là hành động thực tế mà bạn lặp đi lặp lại.

Vì vậy, nếu tập không thay đổi, chỉ truy vấn độ dài một lần.

Không phải với mảng, nhưng với các bộ bản ghi đến từ máy chủ sql tôi đã thấy những cải tiến đáng kể bằng cách không truy vấn số bản ghi mỗi lần lặp. (tất nhiên chỉ làm điều này nếu bạn có thể đảm bảo cho bạn mảng hoặc bộ bản ghi không bị thay đổi trong quá trình này).


Nếu số lượng hồ sơ thay đổi, thì sao? Giả sử có 100 mục và trong khi bạn đang xử lý mục 50, một mục sau # 25 được chèn. Vì vậy, khi bạn xử lý mục # 51, nó giống như số 50 mà bạn đã xử lý và mọi thứ đã sai. Vì vậy, vấn đề không phải là chiều dài thay đổi, nó phổ biến hơn nhiều.
gnasher729

@ gnasher729 một khi bạn có hành vi bất đối xứng, có rất nhiều điều có thể sai. Nhưng có những thứ bạn có thể làm để chống lại điều đó như bắt đầu và giao dịch sql.
Pieter B

2

Ý tưởng xuất hiện rằng độ dài "mảng" có thể thay đổi trong quá trình thực hiện vòng lặp for, nhưng chúng tôi không muốn lặp xa hơn kích thước ban đầu, nhưng tôi không thể tưởng tượng được một kịch bản như vậy.

Những người nói về hiệu suất có thể đúng rằng đây là lý do tại sao nó được viết theo cách đó (người viết theo cách đó có thể không chính xác rằng nó ảnh hưởng đáng kể đến hiệu suất, nhưng đó là một vấn đề khác).

Tuy nhiên, để trả lời phần này của câu hỏi của bạn, tôi nghĩ điều đó rất có thể xảy ra khi mục đích chính của vòng lặp là sửa đổi mảng mà nó lặp. Hãy xem xét một cái gì đó như thế này, trong mã giả:

guests = [];
for (i = 0; i < invitations.length; ++i) {
    if (! invitations[i].is_declined()) {
        guests.append(invitations[i].recipient())
    }
}
// maybe some other stuff to modify the guestlist
for (i = 0, n = guests.length; i < n; ++i) {
    if (guests[i].has_plus_one()) {
        guests.append(guests[i].get_plus_one());
    }
}

Tất nhiên có nhiều cách khác để viết nó. Trong trường hợp này, tôi có thể đã kiểm tra các dấu cộng cùng lúc với việc kiểm tra xem người nhận có chấp nhận lời mời của họ hay không và đưa ra danh sách khách mời đầy đủ một lời mời cùng một lúc. Tôi không nhất thiết muốn kết hợp hai thao tác đó, nhưng tôi không thể nghĩ ngay đến lý do tại sao điều đó chắc chắn sai và do đó thiết kế này là bắt buộc . Thỉnh thoảng, đó là một lựa chọn để xem xét.

Trên thực tế tôi nghĩ rằng điều sai nhất với mã này là thành viên của guestsmảng có nghĩa là những thứ khác nhau ở các điểm khác nhau trong mã. Do đó, tôi chắc chắn sẽ không gọi nó là "mẫu", nhưng tôi không biết rằng nó đủ khiếm khuyết để loại trừ việc làm bất cứ điều gì thuộc loại này :-)


Mảng cũng có thể được sửa đổi bởi một chủ đề khác. Điều này ngăn trình biên dịch tối ưu hóa truy xuất chiều dài. Vì vậy, trong câu hỏi, lập trình viên nói rõ ràng rằng mảng không thay đổi ngay cả trong các luồng khác.
Basilevs

0

Nếu có thể, bạn nên sử dụng một trình vòng lặp đi qua tất cả các phần tử của mảng. Bạn sử dụng mảng chỉ như một chuỗi, không phải là lưu trữ truy cập ngẫu nhiên, do đó, rõ ràng là một trình vòng lặp chỉ thực hiện truy cập tuần tự sẽ nhanh hơn. Hãy tưởng tượng những gì bạn nghĩ là một mảng thực sự là một cây nhị phân, nhưng ai đó đã viết mã xác định "độ dài" bằng cách đếm các phần tử và mã truy cập vào phần tử thứ i, cũng bằng cách duyệt qua phần tử, mỗi phần tử trong O (n ). Một iterator có thể rất nhanh, vòng lặp của bạn sẽ chậm chạp.

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.