2009-09-26 32 views
21

Tôi có một hashset trong C# mà tôi đang loại bỏ nếu một điều kiện được đáp ứng trong khi lặp mặc dù hashset và không thể thực hiện điều này bằng cách sử dụng vòng lặp foreach như dưới đây.HashSet Lặp lại trong khi xóa các mục trong C#

foreach (String hashVal in hashset) 
{ 
    if (hashVal == "somestring") 
    { 
      hash.Remove("somestring"); 
    } 
} 

Vì vậy, làm cách nào để xóa các phần tử trong khi lặp?

Trả lời

44

Sử dụng RemoveWhere phương pháp HashSet thay vì:

hashset.RemoveWhere(s => s == "somestring"); 

Bạn chỉ rõ một điều kiện/vị như tham số để phương pháp. Bất kỳ mục nào trong bộ băm phù hợp với vị từ sẽ bị xóa.

Điều này tránh được vấn đề sửa đổi băm trong khi nó đang được lặp lại.


Đáp lại bình luận của bạn:

's' đại diện cho mục hiện đang được đánh giá từ bên trong HashSet.

Đoạn mã trên tương đương với:

hashset.RemoveWhere(delegate(string s) {return s == "somestring";}); 

hay:

hashset.RemoveWhere(ShouldRemove); 

public bool ShouldRemove(string s) 
{ 
    return s == "somestring"; 
} 

EDIT: Something vừa mới xảy ra với tôi: kể từ HashSet là một tập hợp không chứa giá trị trùng lặp, chỉ cần gọi hashset.Remove("somestring") là đủ. Không cần phải làm điều đó trong một vòng lặp vì sẽ không bao giờ có nhiều hơn một trận đấu duy nhất.

+0

Cảm ơn những gì sẽ đại diện cho? – aHunter

+0

's' thể hiện mục hiện tại từ bên trong hashset đang được đánh giá. Xem câu trả lời được cập nhật. – adrianbanks

1

Thông thường khi tôi muốn để lặp qua một cái gì đó và loại bỏ các giá trị tôi sử dụng:

For (index = last to first) 
     If(ShouldRemove(index)) Then 
      Remove(index) 
+0

Cảm ơn tôi biết rằng tôi có thể sử dụng vòng lặp for cho phép bạn không thể truy cập vào HashSet bằng cách sử dụng vị trí chỉ mục theo cách này. Nếu tôi đã sử dụng C + + thì tôi chỉ đơn giản là sử dụng con trỏ đặt tôi không thể làm điều này trong C#. – aHunter

+0

Bạn cũng có thể xem xét sử dụng cấu trúc dữ liệu khác nếu có thể. – Nescio

8

Bạn không thể xóa các mục khỏi bộ sưu tập trong khi lặp lại các mục đó bằng một điều tra viên. Hai cách tiếp cận để giải quyết này là:

  • Vòng ngược so với bộ sưu tập sử dụng thường xuyên được lập chỉ mục cho vòng lặp (mà tôi tin không phải là một lựa chọn trong trường hợp của một HashSet)
  • Vòng qua các bộ sưu tập, thêm các mục phải được loại bỏ vào bộ sưu tập khác, sau đó vòng qua -collection "to-be-xóa" và loại bỏ các mục:

Ví dụ về cách tiếp cận thứ hai:

HashSet<string> hashSet = new HashSet<string>(); 
hashSet.Add("one"); 
hashSet.Add("two"); 

List<string> itemsToRemove = new List<string>(); 
foreach (var item in hashSet) 
{ 
    if (item == "one") 
    { 
     itemsToRemove.Add(item); 
    } 
} 

foreach (var item in itemsToRemove) 
{ 
    hashSet.Remove(item); 
} 
+0

Chương trình này đã khá nhiều bộ nhớ nên tôi không muốn sử dụng một danh sách khác. Cảm ơn – aHunter

+0

Tôi sẽ tránh sử dụng hai vòng lặp foreach - một vòng lặp foreach là đủ, xem câu trả lời của tôi – javapowered

4

tôi sẽ tránh sử dụng vòng lặp hai foreach - một foreach vòng lặp là đủ:

HashSet<string> anotherHashSet = new HashSet<string>(); 
foreach (var item in hashSet) 
{ 
    if (!shouldBeRemoved) 
    { 
     anotherSet.Add(item); 
    } 
} 
hashSet = anotherHashSet; 
0

Mặc dù tôi không thích nó cá nhân bạn có thể giải quyết vấn đề này bằng cách sử dụng một OrderedDictionary thay vì một HashSet và thêm null như các giá trị trong khóa/cặp giá trị. Điều này sẽ cho phép bạn lặp qua các mục theo chỉ mục bằng cách sử dụng vòng lặp for.

OrderedDictionary d = new OrderedDictionary; 
//Code to fill it up 
for (int i = 0;i < d.Count;i++) 
    if (shouldRemove(d[i])) 
     d.RemoveAt(i); 

Lưu ý rằng không giống như các kiểu dữ liệu khác không có phiên bản generic của OrderedDictionary sẵn do thực tế rằng nó sẽ làm cho nó không thể phân biệt giữa việc truy cập bởi chỉ số hoặc mục trong trường hợp các phím là các số nguyên. Điều này có thể dẫn đến rất nhiều quá trình truyền và kiểm tra kiểu để chỉ sử dụng nó nếu các giải pháp trên không phải là một tùy chọn.

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