Distinto in Linq in base a un solo campo della tabella


133

Sto cercando di utilizzare .distinct in Linq per ottenere risultati in base a un campo della tabella (quindi non è necessario un intero record duplicato dalla tabella).

So che scrivere query di base usando distinti come segue:

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

ma ho bisogno di risultati che r.textnon siano duplicati.


È necessario specificare quale campo si vuole essere distinti, vedere msdn.microsoft.com/en-us/library/bb348436.aspx
Antarr Byrd

Risposte:


300

Prova questo:

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

Questo raggrupperà la tabella Texte utilizzerà la prima riga di ciascun gruppo risultante in righe dove Textè distinto.


2
Cosa succede se groupby ha più di 1 campo?

6
@ user585440: In tal caso, usi un tipo anonimo in questo modo:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth

2
Sì, hai ragione e l'ho già trovato. Grazie comunque. E trovo anche che Select (x => x.First ()) può causare crash. È meglio passare a Seleziona (x => x.FirstOrDefault ());

6
Ho dovuto usare FirstOrDefault altrimenti si è verificato un errore di runtime
TruthOf42

2
@ TruthOf42 È piuttosto improbabile. GroupBynon crea gruppi vuoti, vedi il mio commento precedente. Molto probabilmente, il tuo codice contiene più di quello che vedi qui. Forse hai Whereanche un o una condizione per il First.
Daniel Hilgarth,

26

MoreLinq ha un metodo DistinctBy che puoi usare:

Ti permetterà di fare:

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

L'implementazione del metodo (a meno della convalida dell'argomento) è la seguente:

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

mi dispiace non volevo usare equalityComparer.
Megha Jain,

@MeghaJain Bene, uno verrà usato indipendentemente, come ne ha GroupBybisogno anche uno. Entrambi i metodi utilizzeranno il valore predefinito EqualityComparerse non ne viene fornito nessuno.
Servito il

9
Bene, correggimi se sbaglio, ma questo distinto qui è fatto in memoria, non in DB? Questo non potrebbe portare a scansioni complete indesiderate?
Kek

@Kek. No, a causa del rendimento, ti fermerai al primo elemento distinto. Alla fine, sì, caricherai ciascuna chiave in HashSet, ma poiché è IEnumerable in e IEnumerable out, otterrai solo quegli elementi. Se stai parlando di LINQ to SQL, allora sì, questo eseguirà una scansione della tabella.
PRMan,

12

ma ho bisogno di risultati in cui r.text non sia duplicato

Sembra che tu voglia questo:

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

Questo selezionerà le righe in cui Textè unico.


7

La risposta di Daniel Hilgarth sopra porta a System.NotSupportedun'eccezione con Entity-Framework . Con Entity-Framework , deve essere:

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

3

Ci sono molte discussioni su questo argomento.

Puoi trovarne uno qui :

Uno dei suggerimenti più popolari è stato il metodo Distinct che utilizza un'espressione lambda come parametro, come ha sottolineato @Servy.

L'architetto capo di C #, Anders Hejlsberg, ha suggerito la soluzione qui . Spiegando anche perché il team di progettazione del framework ha deciso di non aggiungere un sovraccarico del metodo Distinct che prende un lambda.


2

Da quello che ho trovato, la tua domanda è per lo più corretta. Basta cambiare "select r" in "select r.Text" è tutto e questo dovrebbe risolvere il problema. Ecco come MSDN ha documentato come dovrebbe funzionare.

Ex:

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

hai cambiato la frase "select" che potrebbe non essere desiderata in questo caso
faza

1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });

-2

prova questo codice:

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

-5

Puoi provare questo:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.