2010-08-08 84 views
53

tôi có một danh sáchlàm thế nào để kiểm tra xem đối tượng đã tồn tại trong một danh sách

List<MyObject> myList 

và tôi đang bổ sung thêm mục vào danh sách và tôi muốn kiểm tra xem đối tượng đó là đã có trong danh sách.

vì vậy trước khi tôi làm điều này:

myList.Add(nextObject); 

tôi muốn để xem nếu nextObject là đã có trong danh sách.

đối tượng "MyObject" có một số thuộc tính nhưng so sánh dựa trên kết hợp trên hai thuộc tính.

cách tốt nhất để làm một kiểm tra trước khi tôi thêm một "MyObject" mới để thsi danh sách "MyObject" s

giải pháp duy nhất tôi nghĩ ra là phải thay đổi từ một danh sách để một cuốn từ điển và họ là những gì làm cho chìa khóa một chuỗi liên kết của các thuộc tính (điều này có vẻ hơi unelegant)

bất kỳ giải pháp làm sạch nào khác sử dụng danh sách hoặc LINQ hoặc cái gì khác?

Trả lời

96

Tùy thuộc vào nhu cầu của tình huống cụ thể. Ví dụ, cách tiếp cận từ điển sẽ là khá tốt giả:

  1. Danh sách này là tương đối ổn định (không có nhiều chèn/xóa, mà từ điển không được tối ưu hóa cho)
  2. Danh sách này là khá lớn (nếu không chi phí của từ điển là vô nghĩa).

Nếu ở trên là không đúng đối với tình hình của bạn, chỉ cần sử dụng Any():

Item wonderIfItsPresent = ... 
bool containsItem = myList.Any(item => item.UniqueProperty == wonderIfItsPresent.UniqueProperty);' 

này sẽ liệt kê qua danh sách cho đến khi nó tìm thấy một trận đấu, hoặc cho đến khi nó đạt đến kết thúc.

+0

Việc sử dụng một đại biểu ngữ cho list.exists là một giải pháp khác thấy dưới đây, nhưng nếu bạn có danh sách lớn và giá trị quan trọng với một từ điển sẽ nhanh hơn nhiều vì nó là một bảng băm! Thưởng thức – Doug

39

Nếu đó là duy trì sử dụng những 2 thuộc tính, bạn có thể:

bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat"); 
4

Một điểm cần lưu ý là bạn phải đảm bảo rằng chức năng bình đẳng của bạn là như bạn mong đợi. Bạn nên ghi đè phương thức equals để thiết lập những thuộc tính nào của đối tượng của bạn phải khớp với hai trường hợp được xem là bằng nhau.

Sau đó, bạn chỉ có thể làm mylist.contains (item)

6

Bạn có chắc chắn bạn cần có một danh sách trong trường hợp này? Nếu bạn đang điền danh sách có nhiều mục, hiệu suất sẽ bị myList.Contains hoặc myList.Any; thời gian chạy sẽ là bậc hai. Bạn có thể muốn xem xét sử dụng cấu trúc dữ liệu tốt hơn.Ví dụ,

public class MyClass 
    { 
     public string Property1 { get; set; } 
     public string Property2 { get; set; } 

    } 

    public class MyClassComparer : EqualityComparer<MyClass> 
    { 
     public override bool Equals(MyClass x, MyClass y) 
     { 
      if(x == null || y == null) 
       return x == y; 

      return x.Property1 == y.Property1 && x.Property2 == y.Property2; 
     } 

     public override int GetHashCode(MyClass obj) 
     { 
      return obj == null ? 0 : (obj.Property1.GetHashCode()^obj.Property2.GetHashCode()); 
     } 
    } 

Bạn có thể sử dụng một HashSet theo cách sau đây:

var set = new HashSet<MyClass>(new MyClassComparer()); 
    foreach(var myClass in ...) 
    set.Add(myClass); 

Tất nhiên, nếu định nghĩa này bình đẳng cho MyClass là 'phổ thông', bạn không cần phải viết một thực hiện IEqualityComparer ; bạn chỉ có thể ghi đè lên số GetHashCodeEquals trong chính lớp đó.

+0

Vâng, bool for V là yêu thích của tôi. Cho rằng vấn đề, nó đã không được lâu trước đây (eh, khoảng 3 tuần) mà HashSet đã không có sẵn cho tôi bởi vì tôi đã làm việc trên mã 2.0, và tôi giảm trong việc thực hiện Mono của HashSet vì nó rất darn hữu ích :) –

3

Edit: Tôi đã thứ nhất nói:


Có gì không thanh nha về các giải pháp từ điển. Nó có vẻ hoàn toàn thanh lịch với tôi, đặc biệt vì bạn chỉ cần đặt bộ so sánh trong việc tạo ra từ điển.


Tất nhiên, không phù hợp để sử dụng thứ gì đó làm khóa khi đó cũng là giá trị.

Vì vậy, tôi sẽ sử dụng một HashSet. Nếu các hoạt động sau này yêu cầu lập chỉ mục, tôi sẽ tạo một danh sách từ khi quá trình Thêm được thực hiện, nếu không, chỉ cần sử dụng hàm băm.

+0

Tôi sẽ chỉ sử dụng điều này nếu danh sách các đối tượng là rất lớn kể từ khi một bảng băm và họ là rất tốt cho tra cứu nhanh. – Doug

3

Đây là ứng dụng bảng điều khiển nhanh để mô tả khái niệm về cách giải quyết vấn đề của bạn.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication3 
{ 
    public class myobj 
    { 
     private string a = string.Empty; 
     private string b = string.Empty; 

     public myobj(string a, string b) 
     { 
      this.a = a; 
      this.b = b; 
     } 

     public string A 
     { 
      get 
      { 
       return a; 
      } 
     } 

     public string B 
     { 
      get 
      { 
       return b; 
      } 
     } 
    } 


    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<myobj> list = new List<myobj>(); 
      myobj[] objects = { new myobj("a", "b"), new myobj("c", "d"), new myobj("a", "b") }; 


      for (int i = 0; i < objects.Length; i++) 
      { 
       if (!list.Exists((delegate(myobj x) { return (string.Equals(x.A, objects[i].A) && string.Equals(x.B, objects[i].B)) ? true : false; }))) 
       { 
        list.Add(objects[i]); 
       } 
      } 
     } 
    } 
} 

Tận hưởng!

37

Chỉ cần sử dụng phương pháp Contains. Lưu ý rằng nó hoạt động dựa trên các chức năng bình đẳng Equals

bool alreadyExist = list.Contains(item); 
+3

Điều này không hiệu quả đối với tôi, nó luôn luôn nói rằng nó không tồn tại – Si8

+1

@ Si8 Nếu bạn đang cố gắng so sánh các đối tượng, bạn phải chắc chắn rằng IEquatable thực hiện .Equals được thực hiện đúng cho loại đối tượng của bạn. Nếu không, bạn sẽ không so sánh nội dung của đối tượng. Xem liên kết Chứa Ahmad được chỉ ra để biết ví dụ về cách thực hiện điều này. –

0

đơn giản nhưng nó hoạt động

MyList.Remove(nextObject) 
MyList.Add(nextObject) 

hoặc

if (!MyList.Contains(nextObject)) 
    MyList.Add(nextObject); 
+0

Tùy chọn thứ hai được bao gồm bởi câu trả lời của Ahmad –

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