Remove Duplicate Items From Generic Collection


If you need to remove the duplicate items from a generic list, you can use the LINQ 'sDistinct method and pass an instance of IEqualityComparer as an argument to it. Using IEqualityComparer you can define your rules for identifying duplicates.

Suppose you have a class

public class Contact
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddress { get; set; }
}

And you have the requirement where you can tell which property of your object to compare. So the comparer class goes as below

public sealed class EqualityComparer<T, TKey> : IEqualityComparer<T>
{
    private readonly Func<T, TKey> _keySelector;
    private readonly IEqualityComparer<TKey> _keyComparer;
    public EqualityComparer(Func<T, TKey> keySelector, IEqualityComparer<TKey> keyComparer)
    {
        if (null == keySelector) throw new ArgumentNullException("keySelector");
        _keySelector = keySelector;
        _keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
    }
    public EqualityComparer(Func<T, TKey> keySelector)
        : this(keySelector, null)
    {
    }
    public bool Equals(T x, T y)
    {
        if (!GenericHelper.HasValue(x)) return !GenericHelper.HasValue(y);
        if (!GenericHelper.HasValue(y)) return false;
        TKey xKey = _keySelector(x);
        TKey yKey = _keySelector(y);
        if (!GenericHelper.HasValue(xKey)) return !GenericHelper.HasValue(yKey);
        if (!GenericHelper.HasValue(yKey)) return false;
        return _keyComparer.Equals(xKey, yKey);
    }
    public int GetHashCode(T obj)
    {
        if (!GenericHelper.HasValue(obj)) return 0;
        TKey key = _keySelector(obj);
        if (!GenericHelper.HasValue(key)) return 0;
        return _keyComparer.GetHashCode(key);
    }
}
public static class EqualityComparer
{
    public static IEqualityComparer<T> Create<T, TKey>(Func<T, TKey> keySelector, IEqualityComparer<TKey> keyComparer)
    {
        if (null == keySelector) throw new ArgumentNullException("keySelector");
        return new EqualityComparer<T, TKey>(keySelector, keyComparer);
    }
    public static IEqualityComparer<T> Create<T, TKey>(Func<T, TKey> keySelector)
    {
        return Create(keySelector, null);
    }
}

And sample console code:

static void Main(string[] args)
{
    //create a list of custom class
    List<Contact> collection = new List<Contact>();
    //create a list of integer items
    List<int> list = new List<int>();
    //populate the lists
    #region populate the lists
    #endregion
    //create the custom comparers
    IEqualityComparer<Contact> customComparer = EqualityComparer.Create((Contact c) => c.EmailAddress);
    IEqualityComparer<int> customComparer2 = EqualityComparer.Create((int l) => l);
    //print the distinct items form contact collection
    foreach (Contact c in collection.Distinct(customComparer))
    {
        Console.WriteLine("Name: {0} {1}, Email: {2}", c.FirstName, c.LastName, c.EmailAddress);
    }
    //print the distinct items from int collection
    foreach (int c in list.Distinct(customComparer2))
    {
        Console.WriteLine(c.ToString());
    }
    Console.ReadLine();
}