52 votes

Pourquoi n'est-il pas Linq méthode pour renvoyer des valeurs distinctes en un prédicat?

Je veux obtenir les valeurs distinctes dans une liste, mais pas par le standard de comparaison d'égalité.

Ce que je veux faire, c'est quelque chose comme ceci:

return myList.Distinct( (x, y) => x.Url == y.Url );

Je ne peux pas, il n'y a aucune méthode d'extension dans Linq qui va le faire, un qui prend un IEqualityComparer.

Je peux pirater autour d'elle avec ceci:

return myList.GroupBy( x => x.Url ).Select( g => g.First() );

Mais qui semble en désordre. Il n'a pas également tout à fait faire la même chose - je ne peux l'utiliser ici parce que j'ai une clé unique.

Je pourrais aussi ajouter le mien:

public static IEnumerable<T> Distinct<T>( 
    this IEnumerable<T> input, Func<T,T,bool> compare )
{
    //write my own here
}

Mais il semble que plutôt que d'écrire quelque chose qui devrait être là en premier lieu.

Quelqu'un sait pourquoi cette méthode n'est pas là?

Ai-je raté quelque chose?

58voto

Jon Skeet Points 692016

C'est ennuyeux, certainement. C'est aussi une partie de mon "MoreLINQ" projet qui, je doit prêter attention à un point :) Il y a beaucoup d'autres activités qui font sens, lorsqu'ils agissent sur une projection, mais le retour de l'original - MaxBy et MinBy viennent à l'esprit.

Comme vous le dites, il est facile d'écrire - même si je préfère le nom de "DistinctBy" pour correspondre à OrderBy etc. Voici mon application si vous êtes intéressé:

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

36voto

David B Points 53123

Mais qui semble en désordre.

Ce n'est pas sale, c'est correct.

  • Si vous souhaitez Distinct de Programmeurs Prénom et il y a quatre de David, lequel voulez-vous?
  • Si vous Group de programmeurs Prénom et prendre l' First , c'est clair ce que vous voulez faire dans le cas de quatre de David.

Je ne peux l'utiliser ici parce que j'ai une clé unique.

Vous pouvez faire un des multiples "distinct" avec le même motif:

return myList
  .GroupBy( x => new { x.Url, x.Age } )
  .Select( g => g.First() );

3voto

SVC Points 31

Jon, votre solution est assez bonne. Un changement mineur mais. Je ne pense pas que nous avons besoin de EqualityComparer.Par défaut là. Voici ma solution (bien sûr, le point de départ était Jon Skeet de la solution)

    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
    {
        //TODO All arg checks
        HashSet<TKey> keys = new HashSet<TKey>();
        foreach (T item in source)
        {
            TKey key = keySelector(item);
            if (!keys.Contains(key))
            {
                keys.Add(key);
                yield return item;
            }
        }
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X