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.