Why is there no Linq method to return distinct values by a predicate?

c#, distinct, linq

Solution

It's annoying, certainly. It's also part of my "MoreLINQ" project which I must pay some attention to at some point :) There are plenty of other operations which make sense when acting on a projection, but returning the original - MaxBy and MinBy spring to mind.

As you say, it's easy to write - although I prefer the name "DistinctBy" to match OrderBy etc. Here's my implementation if you're interested:

    public static IEnumerable<TSource> DistinctBy<TSource, TKey>
        (this IEnumerable<TSource> source,
         Func<TSource, TKey> keySelector)
    {
        return source.DistinctBy(keySelector,
                                 EqualityComparer<TKey>.Default);
    }

    public static IEnumerable<TSource> DistinctBy<TSource, TKey>
        (this IEnumerable<TSource> source,
         Func<TSource, TKey> keySelector,
         IEqualityComparer<TKey> comparer)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (keySelector == null)
        {
            throw new ArgumentNullException("keySelector");
        }
        if (comparer == null)
        {
            throw new ArgumentNullException("comparer");
        }
        return DistinctByImpl(source, keySelector, comparer);
    }

    private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>
        (IEnumerable<TSource> source,
         Func<TSource, TKey> keySelector,
         IEqualityComparer<TKey> comparer)
    {
        HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
        foreach (TSource element in source)
        {
            if (knownKeys.Add(keySelector(element)))
            {
                yield return element;
            }
        }
    }

Problem

I want to get the distinct values in a list, but not by the standard equality comparison. What I want to do is something like this: ``` return myList.Distinct( (x, y) => x.Url == y.Url ); ``` I can't, there's no extension method in Linq that will do this - just one that takes an `IEqualityComparer`. I can hack around it with this: ``` return myList.GroupBy( x => x.Url ).Select( g => g.First() ); ``` But that seems messy. It also doesn't quite do the same thing - I can only use it here because I have a single key. I could also add my own: ``` public static IEnumerable<T> Distinct<T>( this IEnumerable<T> input, Func<T,T,bool> compare ) { //write my own here } ``` But that does seem rather like writing something that should be there in the first place. Anyone know why this method isn't there? Am I missing something?

Original source