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.


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.


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

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.


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());

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.


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();

Sie haben die "select"
-Anweisung

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

-2

Versuchen Sie diesen Code:

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

-5

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.