2013-06-26 21 views
28

Nói rằng tôi có như sau:Hãy so sánh hai danh sách Via Một tài sản dùng LINQ

class Widget1{ 
     public int TypeID { get; set; } 
     public string Color { get; set; } 
    } 

    class Widget2 
    { 
     public int TypeID { get; set; } 
     public string Brand { get; set; } 
    } 

    private void test() 
    { 
     List<Widget1> widgets1 = new List<Widget1>(); 
     List<Widget2> widgets2 = new List<Widget2>(); 
     List<Widget1> widgets1_in_widgets2 = new List<Widget1>(); 

     //some code here to populate widgets1 and widgets2 

     foreach (Widget1 w1 in widgets1) 
     { 
      foreach (Widget2 w2 in widgets2) 
      { 
       if (w1.TypeID == w2.TypeID) 
       { 
        widgets1_in_widgets2.Add(w1); 
       } 
      } 
     } 
    } 

Tôi đang sử dụng hai foreach vòng lặp để so sánh danh mục do typeid để cư một danh sách thứ ba. Có cách nào khác sử dụng LINQ để so sánh hai danh sách này thông qua TypeID không? Có lẽ sử dụng Interstect hoặc một số chức năng khác?

Trả lời

33

Điều bạn muốn ở đây là Join.

var widgets1_in_widgets2 = from first in widgest1 
    join second in widgets2 
    on first.TypeID equals second.TypeID 
    select first; 

Intersect có thể nhiều hơn hoặc ít nghĩ đến như một trường hợp đặc biệt của Join nơi hai chuỗi là cùng loại, và do đó có thể được áp dụng cho bình đẳng thay vì cần một dự báo cho từng loại để tạo ra một chìa khóa để so sánh. Với trường hợp của bạn, Intersect không phải là một tùy chọn.

Nếu một ID đặc biệt được nhân đôi trong tập thứ hai của bạn và bạn không muốn món hàng được nhân đôi trong các kết quả sau đó bạn có thể sử dụng một GroupJoin thay vì một Join:

var widgets1_in_widgets2 = from first in widgest1 
    join second in widgets2 
    on first.TypeID equals second.TypeID 
    into matches 
    where matches.Any() 
    select first; 
+0

1 _ "Với trường hợp của bạn, Intersect không phải là một lựa chọn" _ Nó sẽ là một lựa chọn khi một tùy chỉnh 'IEqualityComparer ' sẽ có thể, một loại cơ sở chung. Sau đó, bạn có thể truyền cho [quá tải] này (http://msdn.microsoft.com/en-us/library/bb355408.aspx) hoặc ghi đè 'Equals' +' GetHashCode' trong 'BaseWidget' để so sánh bằng' TypeID 'theo mặc định. –

3

Tham gia có nhược điểm rằng kết quả của bạn có thể bị trùng lặp nếu widgets1 hoặc widgets2 chứa các phần tử có cùng TypeID nhiều hơn một (cũng áp dụng cho mã ban đầu của bạn).

Sau đây sẽ làm chính xác những gì bạn muốn: Trả về tất cả các phần tử từ widgets1 mà một phần tử có TypeID tương ứng tồn tại trong widgets2.

widgets1_in_widgets2 = (from w1 in widgets1 
         where widgets2.Any(w2 => w1.TypeID == w2.TypeID) 
         select w1).ToList() 
+1

Trong khi điều này sẽ tạo ra đầu ra thích hợp, nó sẽ có hiệu suất khá kém khi bạn đang thực hiện tìm kiếm tuyến tính trên một bộ sưu tập cho từng mục trong bộ sưu tập khác. – Servy

+0

'" Tham gia có nhược điểm là kết quả của bạn có thể bị trùng lặp nếu widgets1 hoặc widgets2 chứa các phần tử có cùng TypeID nhiều hơn một.' "Mã trong OP thực sự có kết quả * chính xác * giống như' Tham gia', vì vậy hoặc anh ta không có các khóa trùng lặp trong danh sách hoặc anh ta * muốn * các kết quả trùng lặp. – Servy

+0

@Servy: Điểm tốt, tôi sẽ đề cập đến trong câu trả lời của tôi. Tuy nhiên, việc đặt tên biến làm cho tôi cho rằng điều này là không chủ ý. – Heinzi

28

Bạn có thể làm điều này

widgets2.Where(y=>widget1.Any(z=>z.TypeID==y.TypeID)); 
+4

Trong khi điều này sẽ tạo ra đầu ra thích hợp, nó sẽ có hiệu suất khá kém khi bạn đang thực hiện tìm kiếm tuyến tính trên một tập hợp cho mỗi mục trong bộ sưu tập khác. – Servy

+0

@Servy hmmm..indeed – Anirudha

+1

Thay đổi đơn giản nhất đơn giản là lưu trữ TypeID của một trong các tập hợp trong một 'HashSet' có thể tìm kiếm nhanh hơn nhiều. Một sự thay đổi có ý nghĩa hơn sẽ chỉ là sử dụng 'Tham gia', như tôi đã cho thấy, mặc dù nó sẽ kết thúc làm khá nhiều điều tương tự dưới mui xe. – Servy

2

Hãy thử sử dụng quá tải của "Where"

var isMatch = !widgets1.Where((w1, index) => w1.TypeId == widgets2[index].TypeId)).Any(); 
+1

Câu trả lời chỉ với mã và không giải thích, đặc biệt là khi câu hỏi đã được trả lời kỹ lưỡng trước – ItamarG3

+0

Bạn có thể cập nhật câu trả lời này để xác định cách khác. Tôi thấy đây là một giải pháp được đề xuất hữu ích trong trường hợp bạn muốn so sánh thứ tự và tránh bất kỳ tìm kiếm tuyến tính nào. – DannyMeister

0

Tôi thích giải pháp này bởi vì nó là đơn giản để đọc trong các mã.

bool result = firstList.All(o => secondList.Any(w => w.Prop1 == o.Prop1 && w.Prop2 == o.Prop2)); 

Xem ví dụ đầy đủ trong fiddle: Fiddle example comparation

+0

Thx, điều này làm việc cho tôi. if (projectIds.All (y => r.ProjectsId.Any (z => z.Equals (y)))) { reports.Add (r); } – Parveen