1476 Stimmen

LINQ's Distinct() für eine bestimmte Eigenschaft

Ich spiele mit LINQ, um es zu lernen, aber ich kann nicht herausfinden, wie Sie verwenden Distinct wenn ich keine einfache Liste habe (eine einfache Liste von ganzen Zahlen ist ziemlich einfach zu machen, das ist nicht die Frage). Wenn ich Folgendes verwenden möchte Unverwechselbar auf eine Liste eines Objekts auf eine o mehr Eigenschaften des Objekts?

Beispiel: Wenn ein Objekt Person , mit Eigenschaft Id . Wie kann ich alle Personen erreichen und verwenden Distinct über sie mit der Eigenschaft Id des Objekts?

Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"

Wie kann ich nur Person1 y Person3 ? Ist das möglich?

Wenn es nicht möglich ist, mit LINQ, was wäre der beste Weg, um eine Liste von haben Person abhängig von einigen seiner Eigenschaften in .NET 3.5?

2422voto

Amy B Punkte 104656

Was ist, wenn ich eine eindeutige Liste erhalten möchte, die auf eine o mehr Eigenschaften?

Einfach! Du willst sie gruppieren und einen Gewinner aus der Gruppe auswählen.

List<Person> distinctPeople = allPeople
  .GroupBy(p => p.PersonId)
  .Select(g => g.First())
  .ToList();

Wenn Sie Gruppen für mehrere Eigenschaften definieren möchten, gehen Sie wie folgt vor:

List<Person> distinctPeople = allPeople
  .GroupBy(p => new {p.PersonId, p.FavoriteColor} )
  .Select(g => g.First())
  .ToList();

Hinweis: Bestimmte Abfrageanbieter sind nicht in der Lage aufzulösen, dass jede Gruppe mindestens ein Element haben muss, und dass First die geeignete Methode ist, um in dieser Situation aufzurufen. Wenn Sie mit einem solchen Abfrageanbieter arbeiten, kann FirstOrDefault helfen, Ihre Abfrage durch den Abfrageanbieter zu bringen.

Anmerkung2: Betrachten Sie diese Antwort für einen EF Core (vor EF Core 6) kompatiblen Ansatz. https://stackoverflow.com/a/66529949/8155

2 Stimmen

@ErenErsonmez sicher. Mit meinem geposteten Code, wenn verzögerte Ausführung gewünscht ist, lassen Sie den ToList-Aufruf.

7 Stimmen

Sehr gute Antwort! Hat mir wirklich bei Linq-to-Entities aus einer Sql-Ansicht geholfen, wo ich die Ansicht nicht ändern konnte. Ich musste FirstOrDefault() anstelle von First() verwenden - alles ist gut.

0 Stimmen

Wie wäre es mit dem Aufruf von IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)?

1529voto

Jon Skeet Punkte 1325502

エディテージ : Dies ist jetzt Teil der MehrLINQ .

Was Sie brauchen, ist ein effektives "distinct-by". Ich glaube nicht, dass es Teil von LINQ ist, wie es steht, obwohl es ziemlich einfach zu schreiben ist:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (seenKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

Um also die unterschiedlichen Werte zu finden, indem man nur die Id können Sie verwenden:

var query = people.DistinctBy(p => p.Id);

Und um mehrere Eigenschaften zu verwenden, können Sie anonyme Typen verwenden, die die Gleichheit entsprechend implementieren:

var query = people.DistinctBy(p => new { p.Id, p.Name });

Ungetestet, aber es sollte funktionieren (und es kompiliert jetzt zumindest).

Es wird jedoch der Standard-Vergleicher für die Schlüssel angenommen - wenn Sie einen Gleichheits-Vergleicher übergeben möchten, übergeben Sie ihn einfach an die HashSet Konstrukteur.

0 Stimmen

Dies ist eine gute Lösung, wenn man davon ausgeht, dass bei mehreren nicht unterscheidbaren Werten (wie in diesem Beispiel) der erste Wert zurückgegeben werden soll, den man in der Aufzählung sieht.

0 Stimmen

Ja, das habe ich aufgrund der Frage auch angenommen. Wenn er nach Person2 und Person3 gefragt hätte, wäre es schwieriger gewesen :)

0 Stimmen

Jon, ich habe eine ernsthafte Frage, wahrscheinlich auf Linq-Design-Prinzipien Du nimmst eine IEnumerable und Iteration über es, bedeutet das nicht, dass seine nicht passend, dies zusammen mit Linq zu verwenden, oder mit anderen Worten doesnt dies verderben alle die Güte der aufgeschobenen Ausführung? Ich würde sagen, dass das Nehmen einer ICollection als Parameter ist besser, da der Aufrufer direkt weiß, dass der Linq-Ausdruck ausgeführt wird und keine Magie/Nebenwirkung innerhalb der Methode stattfindet. Ich habe manchmal das Gefühl, dass die Idee der Vermischung von Lazy Execution mit dem ansonsten imperativen Stil von C# kaputt ist :(

128voto

karcsi Punkte 1173

Verwendung:

List<Person> pList = new List<Person>();
/* Fill list */

var result = pList.Where(p => p.Name != null).GroupBy(p => p.Id).Select(grp => grp.FirstOrDefault());

El where hilft Ihnen, die Einträge zu filtern (könnte komplexer sein) und die groupby y select die eindeutige Funktion erfüllen.

3 Stimmen

Perfekt, und funktioniert ohne Erweiterung von Linq oder Verwendung einer anderen Abhängigkeit.

0 Stimmen

Eine großartige Antwort hier. Danke

0 Stimmen

Eine einfache und treffende Antwort. Daumen hoch!

90voto

Chuck Rostance Punkte 6622

Sie können auch eine Abfragesyntax verwenden, wenn Sie wollen, dass es wie LINQ aussieht:

var uniquePeople = from p in people
                   group p by new {p.ID} //or group by new {p.ID, p.Name, p.Whatever}
                   into mygroup
                   select mygroup.FirstOrDefault();

4 Stimmen

Hmm meine Gedanken sind sowohl die Abfrage-Syntax und die fließende API-Syntax sind genauso LINQ wie jeder andere und seine nur Vorliebe über welche Leute verwenden. Ich selbst bevorzuge die fließende API, so dass ich betrachten würde, dass mehr LINK-Like, aber dann schätze ich, dass subjektiv ist

0 Stimmen

LINQ-ähnlich hat nichts mit Vorliebe zu tun, "LINQ-ähnlich" zu sein hat damit zu tun, wie eine andere Abfragesprache auszusehen, die in C# eingebettet ist, ich bevorzuge die fließende Schnittstelle, die von Java-Streams kommt, aber es ist NICHT LINQ-ähnlich.

0 Stimmen

Ausgezeichnet!! Sie sind mein Held!

88voto

Ivan Punkte 1729

Ich denke, das ist ausreichend:

list.Select(s => s.MyField).Distinct();

81 Stimmen

Was ist, wenn er sein gesamtes Objekt zurück braucht, nicht nur dieses bestimmte Feld?

1 Stimmen

Was genau ist das Objekt der verschiedenen Objekte, die denselben Eigenschaftswert haben?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X