Unterscheidet sich in Linq anhand nur eines Feldes der Tabelle

133

Ich versuche, .distinct in Linq zu verwenden, um Ergebnisse basierend auf einem Feld der Tabelle zu erhalten (daher sind keine vollständigen doppelten Datensätze aus der Tabelle erforderlich).

Ich weiß, dass ich grundlegende Abfragen wie folgt schreibe:

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

aber ich brauche Ergebnisse, bei denen r.textnicht dupliziert wird.

Megha Jain
quelle
Sie müssen angeben, welches Feld Sie unterscheiden möchten, siehe msdn.microsoft.com/en-us/library/bb348436.aspx
Antarr Byrd

Antworten:

300

Versuche dies:

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

Dadurch wird die Tabelle nach gruppiert Textund die erste Zeile aus jeder Gruppe verwendet, was zu Zeilen führt, in denen sie Textunterschiedlich sind.

Daniel Hilgarth
quelle
2
Was ist, wenn groupby mehr als ein Feld hat?
6
@ user585440: In diesem Fall verwenden Sie einen anonymen Typ wie folgt:table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());
Daniel Hilgarth
2
Ja, du hast recht und ich habe es bereits gefunden. Danke trotzdem. Und ich finde auch, dass Select (x => x.First ()) zum Absturz führen kann. Es ist besser, zu Select (x => x.FirstOrDefault ()) zu wechseln.
6
Ich musste FirstOrDefault verwenden, sonst gab es einen Laufzeitfehler
TruthOf42
2
@ TruthOf42 Das ist eher unwahrscheinlich. GroupByerstellt keine leeren Gruppen, siehe meinen vorherigen Kommentar. Höchstwahrscheinlich enthält Ihr Code mehr als das, was Sie hier sehen. Vielleicht haben Sie auch eine Whereoder eine Bedingung für die First.
Daniel Hilgarth
26

MoreLinq verfügt über eine DistinctBy- Methode, die Sie verwenden können:

Damit können Sie Folgendes tun:

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

Die Implementierung der Methode (kurz vor der Argumentvalidierung) ist wie folgt:

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;
        }
    }
}
Servieren
quelle
Entschuldigung, ich wollte EqualityComparer nicht verwenden.
Megha Jain
@ MeghaJain Nun, einer wird unabhängig davon verwendet, je nach GroupByBedarf. Beide Methoden verwenden die Standardeinstellung, EqualityComparerwenn keine angegeben ist.
Servy
9
Nun, korrigieren Sie mich, wenn ich falsch liege, aber dies wird hier im Speicher gemacht, nicht in der Datenbank? Könnte dies nicht zu einem unerwünschten vollständigen Scan führen?
Kek
@ Kek. Nein, wegen der Rendite werden Sie beim ersten bestimmten Element anhalten. Ja, schließlich werden Sie jeden Schlüssel in das HashSet laden, aber da er IEnumerable in und IEnumerable out ist, erhalten Sie nur diese Elemente. Wenn Sie über LINQ to SQL sprechen, führt dies einen Tabellenscan durch.
PRMan
12

aber ich brauche Ergebnisse, bei denen r.text nicht dupliziert wird

Klingt so, als ob Sie dies wollen:

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

Dadurch werden Zeilen ausgewählt, in denen das Texteindeutig ist.

Tim Schmelter
quelle
7

Die obige Antwort von Daniel Hilgarth führt zu einer System.NotSupportedAusnahme mit Entity-Framework . Mit Entity-Framework muss es sein:

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

Es gibt viele Diskussionen zu diesem Thema.

Eine davon finden Sie hier :

Einer der beliebtesten Vorschläge war die Distinct-Methode, bei der ein Lambda-Ausdruck als Parameter verwendet wurde, wie @Servy hervorgehoben hat.

Der Chefarchitekt von C #, Anders Hejlsberg, hat hier die Lösung vorgeschlagen . Außerdem wurde erklärt, warum das Framework-Designteam beschlossen hat, keine Überladung der Distinct-Methode hinzuzufügen, für die ein Lambda erforderlich ist.

TKharaishvili
quelle
2

Nach allem, was ich gefunden habe, ist Ihre Anfrage größtenteils korrekt. Ändern Sie einfach "select r" in "select r.Text" und das sollte das Problem lösen. So hat MSDN dokumentiert, wie es funktionieren soll.

Ex:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();
Josh Parks
quelle
Sie haben die "select"
-Anweisung
1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });
bgS
quelle
-2

Versuchen Sie diesen Code:

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

Sie können dies versuchen:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

LucaGuerra
quelle