2008-12-17 31 views

Trả lời

46

Nói chung, các bộ sưu tập mà bạn có thể thực hiện For Each khi triển khai giao diện IEnumerator. Giao diện này chỉ có hai phương thức, MoveNextReset và một thuộc tính, Current.

Về cơ bản, khi bạn sử dụng For Each trên bộ sưu tập, nó gọi hàm MoveNext và đọc giá trị được trả về. Nếu giá trị trả về là True, điều đó có nghĩa là có một phần tử hợp lệ trong bộ sưu tập và phần tử được trả về thông qua thuộc tính Current. Nếu không có thêm phần tử nào trong bộ sưu tập, hàm MoveNext trả về False và lặp lại bị thoát.

Từ lời giải thích ở trên, rõ ràng là các For Each không theo dõi vị trí hiện tại trong bộ sưu tập và do đó câu trả lời cho câu hỏi của bạn là một đoạn ngắn Không.

Nếu, tuy nhiên, bạn vẫn muốn biết liệu bạn có nằm trong phần tử cuối cùng trong bộ sưu tập của mình hay không, bạn có thể thử mã sau đây. Nó kiểm tra (sử dụng LINQ) nếu mục hiện tại là mục cuối cùng.

For Each item in Collection 
    If item Is Collection.Last Then 
     'do something with your last item' 
    End If 
Next 
+0

Một lời giải thích thực sự tốt với giải pháp bao gồm. – Jonathan

+0

cần dấu kiểm –

+0

Nên là câu trả lời được chấp nhận –

1

Kiểm tra xem phần tử có phải là phần tử cuối cùng của vùng chứa hay không.

Tại sao bạn muốn làm điều đó?
Bạn chỉ có thể đặt hướng dẫn sau vòng lặp. (Bạn thực hiện trên phần tử cuối cùng)

12

Có thể sẽ dễ dàng hơn khi sử dụng vòng lặp For thay vì ForEach. Nhưng, tương tự, bạn có thể giữ một truy cập bên trong vòng ForEach của bạn và xem nếu nó bằng yourCollection.Count - 1, thì bạn đang ở trong lần lặp cuối cùng.

+0

Vâng, đây là những gì tôi thường làm gì nếu tôi cần phải làm điều đó nhưng tôi chỉ nghĩ rằng có một số cách thông minh để xác định điều này trong một Cho Mỗi hoặc một cái gì đó. – EdenMachine

0

Nếu bạn bị ràng buộc với IEnumerable. Bạn có phải ở trong vòng lặp foreach không? Nếu không, bạn có thể khai báo một biến ngay trước vòng lặp foreach. Đặt nó trong vòng lặp. Sau đó, sử dụng nó sau khi vòng lặp (nếu nó không null)

6

Với một foreach, bạn không thể biết điều này cho đến khi nó là quá muộn (tức là bạn ra khỏi vòng lặp).

Lưu ý, tôi giả sử bạn đang sử dụng thứ gì đó mà bạn chỉ có giao diện IEnumerable. Nếu bạn có một danh sách, mảng, vv thì hãy làm theo các câu trả lời khác ở đây sử dụng .Count hoặc tương tự để tìm ra có bao nhiêu mục, và do đó bạn có thể theo dõi bạn đang ở đâu trong bộ sưu tập.

Tuy nhiên, chỉ với IEnumerable/IEnumerator, không có cách nào để biết chắc chắn hay không có nhiều hơn, nếu bạn sử dụng foreach.

Nếu bạn cần biết điều này, hãy sử dụng IEnumerable chính mình, đó là những gì foreach làm.

Các giải pháp dưới đây là dành cho C# nhưng nên dịch một cách dễ dàng để VB.NET:

List<Int32> nums = new List<Int32>(); 
nums.Add(1); 
nums.Add(2); 
nums.Add(3); 

IEnumerator<Int32> enumerator = nums.GetEnumerator(); 
if (enumerator.MoveNext()) 
{ 
    // at least one value available 
    while (true) 
    { 
     // make a copy of it 
     Int32 current = enumerator.Current; 

     // determine if it was the last value 
     // if not, enumerator.Current is now the next value 
     if (enumerator.MoveNext()) 
     { 
      Console.Out.WriteLine("not last: " + current); 
     } 
     else 
     { 
      Console.Out.WriteLine("last: " + current); 
      break; 
     } 
    } 
} 
enumerator.Dispose(); 

này sẽ in:

not last: 1 
not last: 2 
last: 3 

Bí quyết là để có một bản sao của giá trị hiện tại, sau đó yêu cầu điều tra viên cố gắng chuyển sang điều tra tiếp theo. Nếu điều đó không thành công, bản sao bạn tạo ra thực sự là giá trị cuối cùng, nếu không thì có nhiều hơn.

2

Câu trả lời ngắn: Bạn có thể không

Long trả lời: Không có gì trong ngữ nghĩa của lệnh For Each tuyên bố cho phép bạn xác định xem bạn đang chạy đầu tiên, cuối cùng hay bất cứ lặp đi lặp lại đặc biệt là.

Đối với mỗi giao diện được xây dựng trong giao diện IEnumerable và IEnumerable <> và hành vi phụ thuộc vào việc triển khai bạn đang gọi. Đó là hợp lệ, mặc dù khó hiểu, cho bộ sưu tập bạn đang lặp lại để trả về các phần tử theo thứ tự khác nhau mỗi lần. May mắn thay, Danh sách <> không làm điều này.

Nếu bạn thực sự cần biết rằng một lần lặp cụ thể là lần cuối, bạn có thể xác định phần tử cuối cùng (trước) và sau đó thực hiện hành động khác khi bạn gặp phải phần tử đó.

Dễ dàng hơn để phát hiện lần lặp lại đầu tiên (giả sử qua boolean) và sau đó thực hiện điều gì đó khác.

Một ví dụ (C#, nhưng VB sẽ tương tự):

StringBuilder result = new StringBuilder(); 
bool firstTime = true; 
foreach(string s in names) 
{ 
    if (!firstTime) 
    { 
     result.Append(", "); 
    } 

    result.Append(s); 
    firstTime = false; 
} 
+0

bạn đang quên firstTime = false; sau vòng lặp đầu tiên. – Dutchie432

+0

Rất tiếc! Cảm ơn bạn đã nắm bắt - hiện đã được khắc phục. – Bevan

1

Nó sẽ được dễ dàng hơn để sử dụng một Đối với loop thay vì một ForEach, tuy nhiên bạn có thể làm một cái gì đó giống như

If item.Equals(itemCollection(itemCollection.Count)) Then 
    ... 
End If 

bên trong vòng lặp ForEach của bạn ... Giả sử đối tượng đã ghi đè đúng phương thức Bằng.

Đây có thể là nguồn tài nguyên nhiều hơn nhiều so với chỉ sử dụng vòng lặp For hoặc theo dõi chỉ mục hiện tại trong một biến riêng biệt.

Tôi không chắc đây có phải là cú pháp chính xác hay không, đã lâu rồi tôi không sử dụng VB.

1

Sử dụng vòng lặp "Cho mỗi" chuẩn mà bạn không thể. Mục đích của vòng lặp "cho mỗi" là cho phép bạn tập trung vào dữ liệu thay cho bộ sưu tập cơ bản.

0

Vâng có được vài workaround Giả sử bạn đang làm việc với CheckBoxList

Sau đó, mẫu mã này có thể giúp:

Dim count As Integer = 0 
Dim totalListCount As Integer = CheckBoxList.Items.Count() 
For Each li In CheckBoxList.Items 
     count += 1 
      // This is the Last Item 
     If count = totalListCount THEN 
      // DO Somthing..... 
     END IF 
NEXT  
1

tôi tiếp tục trở lại với bài này, vì vậy tôi quyết định ngồi suy nghĩ về vấn đề này và tôi nghĩ ra điều này:

For Each obj In myCollection 
     Console.WriteLine("current object: {0}", obj.ToString) 

     If Object.ReferenceEquals(obj, myCollection.Last()) Then 
      Console.WriteLine("current object is the last object") 
     End If 
    Next 

Bạn thậm chí có thể giảm tuyên bố If...Then...End If xuống một dòng nếu bạn muốn. Tôi không chắc chắn nếu gọi .Last() trên mỗi lần lặp lại có tác động lớn đến hiệu suất, nhưng bạn luôn có thể gán nó cho một biến ngoài vòng lặp nếu đó là những gì giúp bạn tỉnh táo vào ban đêm.

+0

+1 tuyệt vời cho sự sáng tạo. Nếu bạn nhận được nhiều phiếu bầu hơn cho điều này, tôi sẽ chuyển câu trả lời này thành câu trả lời. – EdenMachine

+0

Một vấn đề với mã của tôi là nếu bộ sưu tập chứa đối tượng cuối cùng nhiều lần, đối tượng hiện tại có thể vượt qua bài kiểm tra bất kể đó có phải là đối tượng cuối cùng trong chuỗi không. Bạn có thể tự quyết định xem đây là lỗi hay tính năng. Vì lý do này, giữ một truy cập là (thật đáng buồn) vẫn là giải pháp tốt nhất cho đến nay. –

1

mẫu mã này có thể giúp

For Each item in Collection 
    If ReferenceEquals(Collection.Item(Collection.Count - 1), item) Then 
    'do something with your last item' 
    End If 
Next 
0

đây là một điều đơn giản tôi không biết nếu nó là đúng về mặt chính trị nhưng nó hoạt động

for each item in listOfThings 
    if(item = listOfThings.last)then 
     'you found the last loop 
    end if 
next 
Các vấn đề liên quan