Comparing Custom Lists

In this blog, let us see how we can determine if two lists contain the same elements, regardless of their sequence in the lists.

With custom classes, we can easily determine if two lists contain the same elements regardless of sequencing in their respective lists. Let's take a look.
 
Start with a custom class as shown below. Notice how I've used IEquatable to provide a custom implementation of Equals and GetHashCode()
  1. public class StudentModel : IEquatable<StudentModel>  
  2.     {  
  3.         public string FirstName { getset; }  
  4.         public string LastName { getset; }  
  5.   
  6.         public override bool Equals(object obj)  
  7.         {  
  8.             return Equals(obj as StudentModel);  
  9.         }  
  10.   
  11.         public bool Equals(StudentModel other)  
  12.         {  
  13.             return other != null &&  
  14.                    FirstName == other.FirstName &&  
  15.                    LastName == other.LastName;  
  16.         }  
  17.   
  18.         public override int GetHashCode()  
  19.         {  
  20.             var hashCode = 1938039292;  
  21.             hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(FirstName);  
  22.             hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(LastName);  
  23.             return hashCode;  
  24.         }  
  25.   
  26.         public static bool operator ==(StudentModel model1, StudentModel model2)  
  27.         {  
  28.             return EqualityComparer<StudentModel>.Default.Equals(model1, model2);  
  29.         }  
  30.   
  31.         public static bool operator !=(StudentModel model1, StudentModel model2)  
  32.         {  
  33.             return !(model1 == model2);  
  34.         }  
  35.     }  
To override the Equals, GetHashCode() and operators I used the  Quick Actions and Refactoring functionality.  It's available by right-clicking on the Class name, selecting Quick Actions and Refactoring and then selecting Generate Equals and GetHashCode().  It's a quick and consistent way for overriding these methods.
 
From here, let's build a custom class to contain our list using the following code.
  1. public class StudentModels : List<StudentModel>  
  2. {  
  3.     public override bool Equals(object obj)  
  4.     {  
  5.         StudentModels other = (StudentModels)obj;  
  6.         return this.All(x => other.Contains(x)) && other.All(y => this.Contains(y));  
  7.     }  
  8.   
  9. }  
Notice the override of the Equals method.  In that method, the real magic occurs. 
 
A straight comparison of  List1.Equals(List2) will not work. You have to use the .Contains() method in LINQ. Also, take note of the dual comparison from (this.All(x => other.Contains(x)) followed by other.All(y => this.Contains(y)).  Why?
 
If you don't do them both, you aren't going to receive the answer to the question, i.e., does every element in List1 has an equal element in List2 and vice versa. You will only receive an answer to whether or not one list is a subset of the other.
 
Now, let's take a look at the code to perform the comparison.
  1. Framework.Students.StudentModel student1 = new Framework.Students.StudentModel()  
  2. {  
  3.     FirstName = "FirstName1",  
  4. };  
  5.   
  6. Framework.Students.StudentModel student2 = new Framework.Students.StudentModel()  
  7. {  
  8.     FirstName = "FirstName1"  
  9. };  
  10.   
  11. Framework.Students.StudentModels listA = new Framework.Students.StudentModels();  
  12. Framework.Students.StudentModels listB = new Framework.Students.StudentModels();  
  13.   
  14. listA.Add(student1);  
  15. listB.Add(student2);  
  16.   
  17. bool all = listA.Equals(listB);  
In this case, both lists will be equal. We've spun up two StudentModel objects with the same first name and added them to two different lists. From there, .Equals() determines if both lists have the same elements.
 
If you have the following code, the Equals override in StudentModels will return false because we are performing the two passes. Student3 is an element of listB, but not a member of listA.
  1. Framework.Students.StudentModel student1 = new Framework.Students.StudentModel()  
  2. {  
  3.     FirstName = "FirstName1",  
  4. };  
  5.   
  6. Framework.Students.StudentModel student2 = new Framework.Students.StudentModel()  
  7. {  
  8.     FirstName = "FirstName1"  
  9. };  
  10.   
  11. Framework.Students.StudentModel student3 = new Framework.Students.StudentModel()  
  12. {  
  13.     FirstName = "FirstName3"  
  14. };  
  15.   
  16. Framework.Students.StudentModels listA = new Framework.Students.StudentModels();  
  17. Framework.Students.StudentModels listB = new Framework.Students.StudentModels();  
  18.   
  19. listA.Add(student1);  
  20. listB.Add(student2);  
  21. listB.Add(student3);  
  22.   
  23. bool all = listA.Equals(listB);  
That's it. You now have a true representation that the two lists are equal. 
 
One thing to point out is that this method does not perform an element by element comparision. It will not tell you if ListA[0] = ListB[0] and ListA[1] = ListB[1] and so on. It does tell you if ListA[0] is contained in ListB. For a sequenced element comparison, you can use SequenceEqual.
  1. bool areSequencesEqual = listA.SequenceEqual(listB);  
That's it! Happy coding!