.NET Framework supplies few useful interfaces for comparing object. Two of them: IEqualityComparer and IComparer might sound bit confusing at first, so in this article I will explain the difference between them and show them in use.
This interface supports the comparison of objects for equality, but what does it truly mean? To understand what equality of two objects is, let's create simple class, so we can compare it later:
public class Student { public string Name { get; set; } public string School { get; set; } public Student(string name, string school) { this.Name = name; this.School = school; } public override string ToString() { return string.Format("{0} from {1}", this.Name, this.School); } }
Now let's create new class implementing IEqalityComparer interface. I will use generics because I want to avoid boxing and unboxing from object.
Before I start, I need to explain how I want to use my comparer. I will use it to select one student, from each school. We can imagine this as some sort of 'School conference' where we need to select one representative from each group.
public class StudentSchoolEqualityComparer : IEqualityComparer<Student> { #region IEqualityComparer<Student> Members public bool Equals(Student x, Student y) { if (x.School.Equals(y.School)) { return true; } else { return false; } } public int GetHashCode(Student obj) { return base.GetHashCode(); } #endregion }
In the example above we can see the only criterion used to check equality of Student object is School property. It means all students even with different names will be considered as equal if their School property is same. We can test our code as follow:
List<Student> Students = new List<Student>(); Students.Add(new Student("Jon", "University of Southern California")); Students.Add(new Student("Philip", "MIT")); Students.Add(new Student("Mike", "MIT")); Students.Add(new Student("Adam", "Stanford University")); Students.Add(new Student("George", "University of Southern California")); Students.Add(new Student("Jessica", "MIT")); Students.Add(new Student("Peter", "University of Southern California")); Students.Add(new Student("Monica", "Stanford University")); Console.WriteLine("All conference students: "); foreach (Student s in Students) { Console.WriteLine(s); } List<Student> Representatives = new List<Student>(); StudentSchoolEqualityComparer comparer = new StudentSchoolEqualityComparer(); Representatives = Students.Distinct(comparer).ToList(); Console.WriteLine("\nRepresentatives: "); foreach (Student s in Representatives) { Console.WriteLine(s); }
As we can see, even though every Student object is different, our StudentSchoolEqualityComparer class decided to select only three 'unique' entries. Using custom comparer we can easily determine the way when objects are considered as same.
What we should remember about IEqualityComparer interface, is we should use it every time when we want to perform equality comparisons.
This time our task is to sort students based on the name of their school:
public class SchoolNameComparer : IComparer<Student> { #region IComparer<Student> Members public int Compare(Student x, Student y) { if (x.School.Equals(y.School)) { return 0; } else { return x.School.CompareTo(y.School); } } #endregion }
Note: because we decided to compare Student objects based on the string (School), we could also use built-in class CaseInsensitiveComparer:
public int Compare(Student x, Student y) { return (new CaseInsensitiveComparer()).Compare(x.School, y.School); }
Now when our Comparer is ready we can use it to sort List<Student> Students:
Console.WriteLine("Original order of the list: "); foreach (Student s in Students) { Console.WriteLine(s); } Console.WriteLine("\nSorted using SchoolNameComparer comparer: "); SchoolNameComparer schoolComparer = new SchoolNameComparer(); Students.Sort(schoolComparer); foreach (Student s in Students) { Console.WriteLine(s); }
As you can see Student objects are correctly sorted based on the value of School property.
Both interfaces are extremely useful when we have to deal with lists and arrays. They allow us to perform sort and select operations based on any criteria we want. Custom EqalityComparers and Comparers can save a lot of time when we must often select and sort our custom data.
Post new comment