Distinct dans Linq basé sur un seul champ de la table

133

J'essaie d'utiliser .distinct dans Linq pour obtenir un résultat basé sur un champ de la table (donc ne nécessite pas un ensemble d'enregistrements dupliqués de la table).

Je sais écrire une requête de base en utilisant distinct comme suit:

var query = (from r in table1
orderby r.Text
select r).distinct();

mais j'ai besoin de résultats où r.textn'est pas dupliqué.

Megha Jain
la source
Vous devez spécifier le champ que vous souhaitez distinguer, voir msdn.microsoft.com/en-us/library/bb348436.aspx
Antarr Byrd

Réponses:

300

Essaye ça:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

Cela regroupera la table Textet utilisera la première ligne de chaque groupe, ce qui donnera des lignes où Textest distinct.

Daniel Hilgarth
la source
2
Que faire si groupby a plus d'un champ?
6
@ user585440: Dans ce cas, vous utilisez un type anonyme comme ceci:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth
2
Oui, vous avez raison et je l'ai déjà trouvé. Merci quand même. Et je trouve également que Select (x => x.First ()) peut provoquer un crash. Il est préférable de passer à Select (x => x.FirstOrDefault ());
6
J'ai dû utiliser FirstOrDefault ou bien il y avait une erreur d'exécution
TruthOf42
2
@ TruthOf42 C'est plutôt improbable. GroupByne crée pas de groupes vides, voir mon commentaire précédent. Très probablement, votre code contient plus que ce que vous voyez ici. Peut-être que vous avez un Whereaussi ou une condition pour le First.
Daniel Hilgarth
26

MoreLinq a une méthode DistinctBy que vous pouvez utiliser:

Cela vous permettra de faire:

var results = table1.DistictBy(row => row.Text);

L'implémentation de la méthode (à court de validation d'argument) est la suivante:

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;
        }
    }
}
Servy
la source
désolé, je ne souhaitais pas utiliser l'égalitéComparer.
Megha Jain
@MeghaJain Eh bien, un sera utilisé de toute façon, car il en GroupByfaut un aussi. Les deux méthodes utiliseront la valeur par défaut EqualityComparersi aucune n'est fournie.
Servy le
9
Eh bien, corrigez-moi si je me trompe, mais ce distinct ici se fait en mémoire, pas en DB? Cela ne pourrait-il pas conduire à une analyse complète indésirable?
Kek
@Kek. Non, à cause du rendement de rendement, vous vous arrêterez au premier élément distinct. Finalement, oui, vous chargerez chaque clé dans le HashSet, mais comme c'est IEnumerable in et IEnumerable out, vous n'obtiendrez que ces éléments. Si vous parlez de LINQ to SQL, alors oui, cela effectuera une analyse de table.
PRMan
12

mais j'ai besoin de résultats où r.text n'est pas dupliqué

On dirait que vous voulez ceci:

table1.GroupBy(x => x.Text)
      .Where(g => g.Count() == 1)
      .Select(g => g.First());

Cela sélectionnera les lignes où le Textest unique.

Tim Schmelter
la source
7

La réponse de Daniel Hilgarth ci-dessus conduit à une System.NotSupportedexception avec Entity-Framework . Avec Entity-Framework , il faut:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());
Biraj Saha
la source
3

Il y a beaucoup de discussions autour de ce sujet.

Vous pouvez en trouver un ici :

L'une des suggestions les plus populaires a été la méthode Distinct prenant une expression lambda comme paramètre, comme @Servy l'a souligné.

L'architecte en chef de C #, Anders Hejlsberg, a proposé ici la solution . Expliquant également pourquoi l'équipe de conception du framework a décidé de ne pas ajouter une surcharge de méthode Distinct qui prend un lambda.

TKharaishvili
la source
2

D'après ce que j'ai trouvé, votre requête est généralement correcte. Il suffit de changer "select r" en "select r.Text" est tout et cela devrait résoudre le problème. C'est ainsi que MSDN a documenté son fonctionnement.

Ex:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();
Josh Parks
la source
vous avez changé l'instruction "select" qui peut ne pas être souhaitée dans ce cas
faza
1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });
bgS
la source
-2

essayez ce code:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());
HamidReza
la source
-5

Vous pouvez essayer ceci:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

LucaGuerra
la source