2009-07-14 39 views
8

Về cơ bản, tôi muốn xóa một mục khỏi danh sách trong khi đang ở trong vòng lặp foreach. Tôi biết rằng điều này là có thể khi sử dụng một vòng lặp for, nhưng cho các mục đích khác, tôi muốn biết nếu điều này là đạt được bằng cách sử dụng một vòng lặp foreach.Sửa đổi bộ sưu tập khi sử dụng vòng lặp foreach trong C#

Trong python chúng ta có thể đạt được điều này bằng cách làm như sau:

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

for i in a: 
    print i 

    if i == 1: 
     a.pop(1) 

này cung cấp cho các đầu ra sau

>>>1 
3 
4 
5 
6 
7 
8 
9 

Nhưng khi làm một cái gì đó tương tự trong C#, tôi nhận được một InvalidOperationException, tôi đã tự hỏi nếu có một cách để giải quyết vấn đề này, hãy mà không cần chỉ đơn giản là sử dụng vòng lặp for.

Mã trong C# mà tôi sử dụng khi các ngoại lệ được ném:

static void Main(string[] args) 
    { 
    List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9"}); 

    foreach (string Item in MyList) 
    { 
    if (MyList.IndexOf(Item) == 0) 
     { 
     MyList.RemoveAt(1); 
     } 

    Console.WriteLine(Item); 
    } 
    } 

Cảm ơn trước

Trả lời

25

Bạn không thể làm điều này. Từ tài liệu cho IEnumerator<T>:

Điều tra viên vẫn còn hiệu lực miễn là bộ sưu tập vẫn không thay đổi. Nếu thay đổi được thực hiện cho bộ sưu tập, chẳng hạn như thêm, sửa đổi hoặc xóa yếu tố, điều tra viên là không hợp lệ vô hiệu và hành vi của chúng tôi là không xác định.

Alternatives là:

  • Xây dựng một danh sách mới các hạng mục để loại bỏ, sau đó loại bỏ tất cả sau đó
  • Sử dụng một bình thường "cho" vòng lặp và đảm bảo rằng bạn cẩn thận về việc không đi trên cùng một phần tử hai lần hoặc thiếu bất kỳ phần tử nào. (Bạn đã nói bạn không muốn làm điều này, nhưng những gì bạn đang cố gắng để làm sẽ không làm việc.)
  • Xây dựng một bộ sưu tập mới chỉ chứa các yếu tố mà bạn muốn giữ lại

các cuối cùng của những lựa chọn thay thế là giải pháp LINQ-như, nơi bạn muốn thường viết:

var newList = oldList.Where(x => ShouldBeRetained(x)).ToList(); 

(. trong trường hợp ShouldBeRetained là bất cứ điều gì logic bạn muốn, tất nhiên) các cuộc gọi đến ToList() chỉ là cần thiết nếu bạn thực sự muốn nó trong một danh sách. Điều này dẫn đến nhiều mã khai báo thường dễ đọc hơn. Tôi không thể dễ dàng đoán được vòng lặp ban đầu của bạn có nghĩa là gì (có vẻ như hơi lạ vào lúc này) trong khi nếu bạn có thể thể hiện logic hoàn toàn về mặt hàng, nó có thể rõ ràng hơn rất nhiều.

+0

Tôi chủ yếu tự hỏi nếu tôi đã bỏ lỡ một cái gì đó ở đâu đó với cá thể foreach, nhưng nếu nó không thể đạt được, ít nhất nó bây giờ đã được xác nhận! Cảm ơn vì câu trả lời – ThePower

1

Bạn chắc chắn không thể thay đổi bộ sưu tập bằng bất kỳ cách nào khi sử dụng vòng lặp foreach trên đó.

Bạn có thể sử dụng vòng lặp for và tự quản lý chỉ mục hoặc sao chép bộ sưu tập và khi bạn đang lặp lại bản gốc, hãy xóa các mục khỏi bản sao bằng với mục gốc.

Trong cả hai trường hợp, nó không hoàn toàn rõ ràng hoặc thuận tiện :).

6

Nếu tất cả bạn cần là để loại bỏ tất cả các mục đáp ứng một điều kiện bạn có thể sử dụng phương pháp List<T>.RemoveAll:

List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" }); 
MyList.RemoveAll(item => item == "1"); 

Lưu ý rằng điều này sẽ thay đổi danh sách ban đầu.

Các vấn đề liên quan