Compare the two lists of differences

I would like some feedback on how best to write a generic function that allows you to compare two lists. Lists contain class objects, and we would like to iterate over one list, looking for the same element in the second list and report any differences.

We already have a method for comparing classes, so we need feedback on how we can submit a method (shown below) from two lists.

For example, let's say we have a simple class "Employee", which has three properties: name, identifier, department. We want to report the differences between a list and another list.

Note:
Both lists will always contain the same number of items.

As mentioned above, we have a general method that we use to compare two classes, how can we include this method for serving lists, i.e. from another method, iterate over the list and combine classes with a common method ... but how can we find the equivalent class in the second list to go to the next method:

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; } 

Any suggestions or ideas appreciated?

Edit: Orientation is .NET 2.0, so LINQ is out of the question.

+44
list c #
Mar 24 '09 at 0:10
source share
5 answers

.... but how to find the equivalent class in the second list to go to the method below;

This is your actual problem; you must have at least one immutable property, identifier, or something like that in order to identify the corresponding objects in both lists. If you do not have such property, you cannot solve the problem without errors. You can simply try to guess the corresponding objects by making minimal or logical changes.

If you have such a property, the solution becomes very simple.

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



thanks to you and danbruc and Noldorin for your feedback. both lists will be the same length and in the same order. so the method above is close, but can you change this method to pass enum.Current to the method above?

Now I'm confused ... what's the problem? Why not just the following?

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

A call to Math.Min () may even be omitted if equal length is guaranteed.




The Noldorin implementation is, of course, smarter due to the delegation and use of counters instead of using ICollection.

+15
Mar 24 '09 at 0:23
source share

This solution creates a result list containing all the differences from both input lists. You can compare your objects by any property, in my example this is an identifier. The only limitation is that lists must be of the same type:

 var DifferencesList = ListA.Where(x => !ListB.Any(x1 => x1.id == x.id)) .Union(ListB.Where(x => !ListA.Any(x1 => x1.id == x.id))); 
+72
May 9 '11 at 11:09
source share

I think you are looking for a method like this:

 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); } } 

This has not been verified, but should nevertheless do the work. Note that it is especially useful in this method that it is complete, i.e. It can take two sequences of arbitrary (and different) types and return objects of any type.

This solution, of course, assumes that you want to compare the nth element of seq1 with the nth element in seq2 . If you want to match elements in two sequences based on a specific property / comparison, then you will want to do some kind of join (as suggested by danbruc using Enumerable.Join . Let me know if this is not one of these approaches that I then, and maybe I can offer something else.

Edit: Here is an example of how you can use the CompareSequences method with the mapping function that you originally placed.

 // 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()); } 
+6
Mar 24 '09 at 0:30
source share

This approach from Microsoft works very well and provides an opportunity to compare one list with another and switch them to get the difference in each. If you are comparing classes, just add your objects to two separate lists and then do the comparison.

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

+2
Jun 18 '13 at 1:55
source share

I hope I understand your question correctly, but you can do it very quickly with Linq. I assume that universally you will always have the Id property. Just create an interface to provide this.

If you determine that an object has the same changes from class to class, I would recommend passing a delegate that returns true if two objects have the same constant identifier.

Here's how to do it in 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); } 
+1
Mar 24 '09 at 0:45
source share



All Articles