2009-03-24 50 views
44

Tôi muốn một số ý kiến ​​phản hồi về cách chúng ta có thể viết một hàm chung chung để cho phép hai Danh sách được so sánh. Danh sách chứa các đối tượng lớp và chúng tôi muốn lặp qua một danh sách, tìm kiếm cùng một mục trong Danh sách thứ hai và báo cáo bất kỳ sự khác biệt nào.So sánh hai Danh sách cho các khác biệt

Chúng tôi đã có một phương pháp để so sánh các lớp học, vì vậy chúng tôi cần phản hồi về cách chúng tôi có thể cung cấp phương thức (được hiển thị bên dưới) từ hai Danh sách.

Ví dụ: giả sử chúng tôi có lớp "Nhân viên" đơn giản có ba thuộc tính, Tên, ID, Bộ. Chúng tôi muốn báo cáo sự khác biệt giữa Danh sách và Danh sách khác.

Lưu ý:
Cả hai danh sách sẽ luôn chứa cùng một số mục. Như đã đề cập ở trên, chúng ta có một phương pháp chung mà chúng ta sử dụng để so sánh hai lớp, làm thế nào chúng ta có thể kết hợp phương thức này để phục vụ Danh sách, tức là từ một phương thức khác, lặp qua Danh sách và nạp các lớp vào phương thức chung. ... nhưng làm thế nào để chúng ta tìm thấy lớp tương đương trong Danh sách thứ hai để chuyển sang phương thức dưới đây;

public static string CompareTwoClass_ReturnDifferences<T1, T2>(T1 Orig, T2 Dest) 
    where T1 : class 
    where T2 : class 
{ 
    // Instantiate if necessary 
    if (Dest == null) throw new ArgumentNullException("Dest", "Destination class must first be instantiated."); 

    var Differences = CoreFormat.StringNoCharacters; 

    // Loop through each property in the destination 
    foreach (var DestProp in Dest.GetType().GetProperties()) 
    { 
     // Find the matching property in the Orig class and compare 
     foreach (var OrigProp in Orig.GetType().GetProperties()) 
     { 

      if (OrigProp.Name != DestProp.Name || OrigProp.PropertyType != DestProp.PropertyType) continue; 
      if (OrigProp.GetValue(Orig, null).ToString() != DestProp.GetValue(Dest, null).ToString()) 
       Differences = Differences == CoreFormat.StringNoCharacters 
        ? string.Format("{0}: {1} -> {2}", OrigProp.Name, 
                 OrigProp.GetValue(Orig, null), 
                 DestProp.GetValue(Dest, null)) 
        : string.Format("{0} {1}{2}: {3} -> {4}", Differences, 
                   Environment.NewLine, 
                   OrigProp.Name, 
                   OrigProp.GetValue(Orig, null), 
                   DestProp.GetValue(Dest, null)); 
     } 
    } 
    return Differences; 
} 

Bất kỳ đề xuất hoặc ý tưởng nào được đánh giá cao?

Chỉnh sửa: Nhắm mục tiêu .NET 2.0 do đó LINQ không nằm trong câu hỏi.

+0

lol ... không, một cấp cao nhất, hệ thống ứng dụng quan trọng :-) nghiêm túc, cố gắng để thực hiện chức năng này vào một ứng dụng sở thích nhỏ ... tất cả nó học. –

+0

Danh sách có độ dài bằng nhau không? – Noldorin

+0

có, Danh sách có độ dài bằng nhau –

Trả lời

15

.... nhưng làm cách nào để tìm lớp tương đương trong Danh sách thứ hai chuyển sang phương thức bên dưới;

Đây là vấn đề thực tế của bạn; bạn phải có ít nhất một thuộc tính bất biến, một id hoặc một cái gì đó tương tự, để xác định các đối tượng tương ứng trong cả hai danh sách. Nếu bạn không có tài sản như vậy, bạn không thể giải quyết vấn đề mà không có lỗi. Bạn chỉ có thể thử đoán các đối tượng tương ứng bằng cách tìm kiếm các thay đổi nhỏ hoặc hợp lý.

Nếu bạn có tài sản như vậy, giải pháp trở nên thực sự đơn giản.

Enumerable.Join(
    listA, listB, 
    a => a.Id, b => b.Id, 
    (a, b) => CompareTwoClass_ReturnDifferences(a, b)) 

nhờ bạn cả danbruc và Noldorin phản hồi của bạn. cả hai Danh sách sẽ có cùng chiều dài và theo cùng một thứ tự. Vì vậy, phương pháp trên là gần, nhưng bạn có thể sửa đổi phương pháp này để vượt qua enum. Hiện tại với phương pháp tôi đã đăng ở trên không?

Bây giờ tôi đang bối rối ... vấn đề với điều đó là gì? Tại sao không chỉ sau đây?

for (Int32 i = 0; i < Math.Min(listA.Count, listB.Count); i++) 
{ 
    yield return CompareTwoClass_ReturnDifferences(listA[i], listB[i]); 
} 

Cuộc gọi Math.Min() thậm chí có thể bị hủy nếu độ dài bằng nhau được đảm bảo.


Việc triển khai của Noldorin tất nhiên thông minh hơn vì đại biểu và sử dụng điều tra viên thay vì sử dụng ICollection.

+0

ok, giả sử rằng Employee.ID sẽ không bao giờ thay đổi. –

+0

xin lỗi, chúng tôi đang nhắm mục tiêu .NET 2.0. Tôi nên đã làm cho điểm này. –

+0

LINQ * có thể * chạy trên .NET 2.0. Xem http://code.google.com/p/linqbridge/ –

6

Tôi nghĩ rằng bạn đang tìm kiếm một phương pháp như thế này:

public static IEnumerable<TResult> CompareSequences<T1, T2, TResult>(IEnumerable<T1> seq1, 
    IEnumerable<T2> seq2, Func<T1, T2, TResult> comparer) 
{ 
    var enum1 = seq1.GetEnumerator(); 
    var enum2 = seq2.GetEnumerator(); 

    while (enum1.MoveNext() && enum2.MoveNext()) 
    { 
     yield return comparer(enum1.Current, enum2.Current); 
    } 
} 

Đó là chưa được kiểm tra, nhưng nó phải thực hiện công việc dù sao. Lưu ý rằng những gì đặc biệt hữu ích về phương pháp này là nó hoàn toàn chung chung, tức là nó có thể mất hai chuỗi các loại tùy ý (và khác nhau) và trả về các đối tượng thuộc bất kỳ loại nào.

Tất nhiên, giải pháp này giả định rằng bạn muốn so sánh mục thứ n của seq1 với mục thứ n trong seq2. Nếu bạn muốn so khớp các phần tử trong hai chuỗi dựa trên một thuộc tính/so sánh cụ thể, thì bạn sẽ muốn thực hiện một số hoạt động join (như được đề xuất bởi danbruc bằng cách sử dụng Enumerable.Join. Hãy cho tôi biết nếu nó không phải là cách tiếp cận này là khá gì tôi sau và có lẽ tôi có thể đề nghị một cái gì đó khác

Edit:.. Dưới đây là một ví dụ về cách bạn có thể sử dụng phương pháp CompareSequences với chức năng comparer bạn ban đầu được đăng

// Prints out to the console all the results returned by the comparer function (CompareTwoClass_ReturnDifferences in this case). 
var results = CompareSequences(list1, list2, CompareTwoClass_ReturnDifferences); 
int index;  

foreach(var element in results) 
{ 
    Console.WriteLine("{0:#000} {1}", index++, element.ToString()); 
} 
+0

Thao tác này sẽ đi bộ cả hai danh sách một cách đồng bộ nhưng đối tượng có thể không được đặt theo cùng một cách trong cả hai danh sách. –

+0

Vâng, tất nhiên rồi.Tôi không thể thu thập được từ câu hỏi liệu đây có phải là trường hợp hay không, nhưng dù sao tôi cũng chỉ chỉnh sửa bài viết trước khi tôi đọc nhận xét của bạn, vì vậy bây giờ tài sản đã đủ điều kiện ... – Noldorin

+0

nhờ bạn cả danbruc và Noldorin cho bạn Phản hồi. cả hai Danh sách sẽ có cùng độ dài và theo cùng một thứ tự. Vì vậy, phương pháp trên là gần, nhưng bạn có thể sửa đổi phương pháp này để vượt qua enum.Current để phương pháp tôi được đăng ở trên? –

1

Tôi hy vọng rằng tôi đang understing câu hỏi của bạn một cách chính xác, nhưng bạn có thể làm điều này ve nhanh chóng với Linq. Tôi giả định rằng phổ quát bạn sẽ luôn có một tài sản Id. Chỉ cần tạo một giao diện để đảm bảo điều này.

Nếu cách bạn xác định đối tượng là cùng một thay đổi từ lớp này sang lớp khác, tôi khuyên bạn nên chuyển qua một đại biểu trả về true nếu hai đối tượng có cùng id liên tục.

Sau đây là cách để làm điều đó trong LINQ:

List<Employee> listA = new List<Employee>(); 
     List<Employee> listB = new List<Employee>(); 

     listA.Add(new Employee() { Id = 1, Name = "Bill" }); 
     listA.Add(new Employee() { Id = 2, Name = "Ted" }); 

     listB.Add(new Employee() { Id = 1, Name = "Bill Sr." }); 
     listB.Add(new Employee() { Id = 3, Name = "Jim" }); 

     var identicalQuery = from employeeA in listA 
          join employeeB in listB on employeeA.Id equals employeeB.Id 
          select new { EmployeeA = employeeA, EmployeeB = employeeB }; 

     foreach (var queryResult in identicalQuery) 
     { 
      Console.WriteLine(queryResult.EmployeeA.Name); 
      Console.WriteLine(queryResult.EmployeeB.Name); 
     } 
+0

-1 so sánh id không đủ kỹ lưỡng. – aggietech

72

giải pháp này tạo ra một danh sách kết quả, có chứa tất cả những khác biệt từ cả hai danh sách đầu vào. Bạn có thể so sánh các đối tượng của mình theo bất kỳ thuộc tính nào, trong ví dụ của tôi là ID. Hạn chế duy nhất là danh sách cần phải cùng loại:

var DifferencesList = ListA.Where(x => !ListB.Any(x1 => x1.id == x.id)) 
      .Union(ListB.Where(x => !ListA.Any(x1 => x1.id == x.id))); 
+6

Điều này thật tuyệt. Cộng đồng thực sự cho phép bạn để có được một người khác xem về một vấn đề. Cảm ơn bạn! – Jeremy

+1

Hoạt động hoàn hảo! Cảm ơn – Haris

+0

Tôi tin rằng điều này giả định rằng không có bản sao trong một trong hai danh sách? – NStuke

2

Cách tiếp cận này từ Microsoft hoạt động rất tốt và cung cấp tùy chọn để so sánh một danh sách khác và chuyển đổi chúng để có được sự khác biệt trong mỗi người. Nếu bạn đang so sánh các lớp, chỉ cần thêm các đối tượng của bạn vào hai danh sách riêng biệt và sau đó chạy so sánh.

http://msdn.microsoft.com/en-us/library/bb397894.aspx

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