18

Khi xem xét, đôi khi tôi gặp phải loại vòng lặp:Phần tử cuối cùng trong một vòng lặp xứng đáng được xử lý riêng biệt?

i = begin 
while (i != end) {  
    // ... do stuff 
    if (i == end-1 (the one-but-last element)) { 
     ... do other stuff 
    } 
    increment i 
} 

Sau đó, tôi đặt câu hỏi: bạn sẽ viết này?

i = begin 
mid = (end - begin)/2 // (the middle element) 
while (i != end) {  
    // ... do stuff 
    if (i > mid) { 
     ... do other stuff 
    } 
    increment i 
} 

Theo ý kiến ​​của tôi, điều này có ý nghĩa đối với từng yếu tố. Sử dụng cấu trúc này, đối với một số yếu tố bạn làm điều gì đó khác biệt. Vì vậy, tôi kết luận, bạn cần một vòng lặp riêng biệt đối với những yếu tố:

i = begin 
mid = (end - begin)/2 //(the middle element) 
while (i != mid) {  
    // ... do stuff 
    increment i 
} 

while (i != end) { 
    // ... do stuff 
    // ... do other stuff 
    increment i 
} 

Bây giờ tôi thậm chí nhìn thấy một question trên SO về cách viết các if -clause một cách thoải mái ... Và tôi đã buồn: một cái gì đó không phải ở đây.

Tôi có sai không? Nếu vậy, những gì tốt như vậy về việc làm lộn xộn cơ thể vòng lặp với các trường hợp đặc biệt, mà bạn nhận thức được trả trước, tại thời điểm mã hóa?

+0

Tất cả điều này là rất tốt. Tôi có thể cải thiện phong cách làm việc cá nhân của mình. Thx –

+0

"bạn lặp lại vì có điều gì đó thường được thực hiện cho từng yếu tố." Nó phụ thuộc như thế nào chung rằng "cái gì" là. Nó có thể được phổ biến chỉ là tất cả các yếu tố là xe ô tô. Một số có màu xanh, một số khác có màu đỏ. Nếu màu xanh sau đó chọn màu xanh, nếu màu đỏ thì chọn màu đỏ để vẽ. Vì vậy, tại một thời điểm nhất định, các quyết định trong vòng lặp có thể có ý nghĩa mặc dù. Nhưng tại một số điểm, nó sẽ trở nên rõ ràng bạn nên chia vòng lặp. –

+0

@peter_the_oak: Tôi đồng ý rằng bạn đưa ra quyết định dựa trên giá trị bạn gặp phải trong vòng lặp, nhưng không dựa trên chỉ mục. – xtofl

Trả lời

5

@xtofl,

Tôi đồng ý với mối lo ngại của bạn.

Triệu lần tôi gặp sự cố tương tự.

Hoặc nhà phát triển thêm xử lý đặc biệt cho đầu tiên hoặc cho phần tử cuối cùng.

Trong hầu hết các trường hợp, nó là giá trị để chỉ vòng lặp từ startIdx + 1 hoặc endIdx - 1 yếu tố hoặc thậm chí chia một vòng lặp dài thành nhiều vòng ngắn hơn.

Trong trường hợp rất hiếm, bạn không thể chia vòng lặp.

Theo ý kiến ​​của tôi không phổ biến mọi thứ sẽ được xử lý bên ngoài vòng lặp bất cứ khi nào có thể.

1

Tất nhiên, những thứ đặc biệt trong vòng lặp có thể bị kéo ra là ngớ ngẩn. Tôi sẽ không lặp lại do_stuff mặc dù; Tôi sẽ đặt nó vào một hàm hoặc một macro để tôi không sao chép-dán mã.

1

Cái nào hoạt động tốt hơn?

Nếu số lượng mục là rất lớn thì tôi sẽ luôn lặp lại một lần, đặc biệt nếu bạn định thực hiện một số hoạt động trên mọi mục. Chi phí đánh giá điều kiện có khả năng ít hơn lặp hai lần.

Rất tiếc, tất nhiên bạn không lặp lại hai lần ... Trong trường hợp đó, hai vòng là thích hợp hơn. Tuy nhiên, tôi duy trì rằng việc xem xét chính nên được thực hiện. Không cần phải chịu điều kiện trong vòng lặp (N lần) nếu bạn có thể phân vùng công việc bằng thao tác đơn giản của giới hạn vòng lặp (một lần).

+0

Tôi chưa bao giờ đề cập lặp lại hai lần - tôi đã gợi ý chia vòng lặp thành hai phần. – xtofl

10

Tôi biết tôi đã nhìn thấy điều này khi mọi người cố gắng tham gia các yếu tố của một mảng thành một chuỗi bằng dấu phẩy tách:

for(i=0;i<elements.size;i++) { 
    if (i>0) { 
    string += ',' 
    } 
    string += elements[i] 
} 

Bạn có thể có mà nếu điều khoản trong đó, hoặc bạn phải lặp lại trong các chuỗi + = lại dòng ở cuối.

Các giải pháp rõ ràng trong trường hợp này là

string = elements.join(',') 

Nhưng tham gia phương pháp thực hiện cùng một vòng lặp trong nội bộ. Và không phải lúc nào cũng có một phương pháp để làm những gì bạn muốn.

5

Tôi đã nhận ra rằng khi tôi đặt các trường hợp đặc biệt vào vòng lặp for, tôi thường quá thông minh vì lợi ích của chính mình.

2

Tôi nghĩ bạn đúng về vòng lặp đang có ý nghĩa để đối phó với tất cả các yếu tố như nhau. Thật không may đôi khi có những trường hợp đặc biệt mặc dù và những nên được xử lý bên trong vòng lặp xây dựng thông qua nếu báo cáo.

Nếu có nhiều trường hợp đặc biệt, mặc dù bạn có lẽ nên suy nghĩ về việc tìm cách giải quyết hai bộ phần tử khác nhau trong các cấu trúc riêng biệt.

1

Một điều tôi ghét phải thấy là for-case pattern:

for (i=0; i<5; i++) 
{ 
    switch(i) 
    { 
    case 0: 
     // something 
     break; 
    case 1: 
     // something else 
     break; 
    // etc... 
    } 
} 

Tôi đã nhìn thấy điều này trong mã thực.

+0

Nếu các trường hợp chỉ thực hiện theo thứ tự và không có mã phổ biến, điều đó có vẻ ngớ ngẩn. Tuy nhiên, nếu hầu hết các lần lặp được xử lý theo mặc định hoặc mã thông thường và có đủ ngoại lệ để ưu tiên sử dụng lệnh 'switch' thay vì' if', tôi sẽ thấy không có gì sai khi sử dụng 'switch' để xử lý các trường hợp phân tán lẻ (ví dụ: có một vòng lặp đếm từ 1 đến 255 và thực hiện điều gì đó kỳ lạ đối với các giá trị chỉ mục là 7, 8, 9, 10, 12, 13 và 27 có vẻ hơi khốc liệt, nhưng đôi khi các chương trình phải mô hình những thứ có tính chất thực thế giới). – supercat

19

Tôi không nghĩ câu hỏi này nên được trả lời theo nguyên tắc (ví dụ: "trong vòng lặp, xử lý mọi phần tử như nhau"). Thay vào đó, bạn có thể xem xét hai yếu tố để đánh giá liệu việc triển khai có tốt hay xấu:

  1. Hiệu suất thời gian chạy - mã được biên dịch có chạy nhanh hay làm nhanh hơn?
  2. Tính bảo trì mã - Có dễ dàng không (đối với nhà phát triển khác) để hiểu điều gì đang xảy ra ở đây?

Nếu nó nhanh hơn và mã dễ đọc hơn bằng cách thực hiện mọi thứ trong một vòng, hãy thực hiện theo cách đó. Nếu nó chậm hơn và ít có thể đọc được, hãy làm theo cách khác.

Nếu nó nhanh hơn và ít dễ đọc hơn, hoặc chậm hơn nhưng dễ đọc hơn, hãy tìm hiểu xem yếu tố nào quan trọng hơn trong trường hợp cụ thể của bạn và sau đó quyết định cách lặp (hoặc không lặp).

5

Trong đoạn trích cuối cùng bạn đã đăng, bạn đang lặp lại mã cho // .... làm công cụ.

Điều này có nghĩa là giữ 2 vòng khi bạn có bộ hoạt động hoàn toàn khác nhau trên một nhóm chỉ mục khác.

i = begin 
mid = (end - begin)/2 //(the middle element) 
while (i != mid) {  
    // ... do stuff 
    increment i 
} 

while (i != end) { 
    // ... do other stuff 
    increment i 
} 

Đây không phải là trường hợp, bạn vẫn muốn giữ một vòng lặp. Tuy nhiên thực tế vẫn là bạn vẫn lưu (kết thúc - bắt đầu)/2 số so sánh. Vì vậy, nó sẽ tập trung vào việc bạn muốn mã của bạn trông gọn gàng hay bạn muốn lưu một số chu kỳ CPU. Cuộc gọi là của bạn.

0

Trường hợp đặc biệt nên được thực hiện ngoài vòng lặp nếu nó chỉ được thực hiện một lần.

Tuy nhiên, có thể có chỉ mục hoặc một số (các) biến khác dễ dàng hơn để giữ bên trong vòng lặp do phạm vi. Cũng có thể có một lý do theo ngữ cảnh để giữ tất cả các hoạt động trên cơ sở hạ tầng với nhau bên trong cấu trúc điều khiển vòng lặp, mặc dù tôi nghĩ rằng đó là một lập luận yếu về chính nó.

0

Chỉ sử dụng nó theo nhu cầu và tiện lợi. Có như vậy không có đề cập đến điều trị các yếu tố như nhau và có chắc chắn không có hại clubbing các tính năng mà ngôn ngữ cung cấp.

3

Tôi nghĩ bạn đã hoàn toàn đóng đinh. Hầu hết mọi người rơi vào cái bẫy bao gồm các nhánh có điều kiện trong vòng lặp, khi họ có thể làm chúng bên ngoài: chỉ đơn giản là nhanh hơn.

Ví dụ:

if(items == null) 
    return null; 

StringBuilder result = new StringBuilder(); 
if(items.Length != 0) 
{ 
    result.Append(items[0]); // Special case outside loop. 
    for(int i = 1; i < items.Length; i++) // Note: we start at element one. 
    { 
     result.Append(";"); 
     result.Append(items[i]); 
    } 
} 
return result.ToString(); 

Và trường hợp giữa bạn mô tả là chỉ đơn giản khó chịu. Hãy tưởng tượng nếu mã đó phát triển và cần phải được tái cấu trúc thành các phương thức khác nhau.

Trừ khi bạn phân tích cú pháp XML <grin> vòng lặp nên được giữ đơn giản và ngắn gọn nhất có thể.

2

Tôi thích đơn giản, loại trừ yếu tố từ các vòng lặp và đưa ra một điều trị spearate bên ngoài vòng lặp

Đối với ví dụ: Cho phép xem xét trường hợp của EOF

i = begin 
while (i != end -1) {  
    // ... do stuff for element from begn to second last element 
    increment i 
} 

if(given_array(end -1) != ''){ 
    // do stuff for the EOF element in the array 
} 
Các vấn đề liên quan