Distinct nach einem Feld in C#: So entfernen Sie Objektduplikate

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Problem: Distinct() kann nicht nach Feld filtern

\n\n

Stellen Sie sich vor: Sie haben eine Liste von Kunden, und darin haben sich Duplikate per E-Mail eingeschlichen. Sie schreiben:

\n\n
var uniqueClients = clients.Distinct().ToList();
\n\n

Und stellen überrascht fest, dass die Duplikate nicht verschwunden sind. Warum? Weil der Standard-Distinct() ganze Objekte per Referenz (oder per Equals, falls Sie es überschrieben haben) vergleicht. Er weiß nicht, dass für Sie „Eindeutigkeit“ eine eindeutige Email ist, und nicht eine eindeutige Klasseninstanz.

\n\n

Diese Frage ist eine der beliebtesten auf Stack Overflow zu LINQ (über 500.000 Aufrufe). Und heute schauen wir uns 3 funktionierende Methoden an, um dieses Problem in C# zu lösen. Los geht's!

\n\n

Methode 1: GroupBy + First (der Klassiker)

\n\n

Die einfachste und verständlichste Methode, die keine Installation von Drittanbieter-Bibliotheken erfordert. Die Idee: Objekte nach der gewünschten Eigenschaft gruppieren und dann das erste Element aus jeder Gruppe nehmen.

\n\n
var uniqueByEmail = clients\n    .GroupBy(c => c.Email)\n    .Select(g => g.First())\n    .ToList();
\n\n

So funktioniert es:

\n
    \n
  • GroupBy(c => c.Email) — teilt die Sammlung in Gruppen auf, wobei der Schlüssel die E-Mail ist.
  • \n
  • Select(g => g.First()) — nimmt das erste Objekt aus jeder Gruppe.
  • \n
  • Die restlichen Duplikate werden verworfen.
  • \n
\n\n

Vorteile:

\n
    \n
  • Funktioniert „out of the box“ (nur using System.Linq;).
  • \n
  • Selbst für Anfänger intuitiv verständlich.
  • \n
  • Behält die ursprüngliche Reihenfolge der Elemente bei (das zuerst gefundene Objekt bleibt erhalten).
  • \n
\n\n

Nachteile:

\n
    \n
  • Bei großen Datenmengen etwas langsamer (Gruppen müssen erstellt werden).
  • \n
  • Der Code ist etwas ausführlicher als gewünscht.
  • \n
\n\n

Methode 2: MoreLinq und DistinctBy (Eleganz)

\n\n

Wenn Sie keine Angst vor Drittanbieter-Bibliotheken haben, bietet MoreLinq die ideale Methode DistinctBy. Sie macht genau das, was Sie von Distinct erwarten – filtert nach einer Eigenschaft.

\n\n

Installation über NuGet:

\n
Install-Package MoreLinq
\n\n

Verwendung:

\n
using MoreLinq;\n\nvar uniqueByEmail = clients.DistinctBy(c => c.Email).ToList();
\n\n

Eine Zeile – und alles ist erledigt. Intern verwendet DistinctBy ein HashSet und arbeitet in O(n).

\n\n

Vorteile:

\n
    \n
  • Äußerst prägnanter und lesbarer Code.
  • \n
  • Hohe Leistung.
  • \n
  • Die Bibliothek ist gut getestet (über 10 Millionen Downloads).
  • \n
\n\n

Nachteile:

\n
    \n
  • Es muss eine Abhängigkeit zum Projekt hinzugefügt werden.
  • \n
  • Nicht alle Teams erlauben Drittanbieter-Bibliotheken.
  • \n
\n\n

Methode 3: Eigener IEqualityComparer (maximale Kontrolle)

\n\n

Diese Methode eignet sich, wenn Sie keine Bibliothek einbinden möchten, aber die Vergleichslogik an mehreren Stellen wiederverwenden wollen. Wir erstellen unseren eigenen Comparer:

\n\n
public class ClientEmailComparer : IEqualityComparer<Client>\n{\n    public bool Equals(Client x, Client y)\n    {\n        if (ReferenceEquals(x, y)) return true;\n        if (x is null || y is null) return false;\n        return x.Email == y.Email;\n    }\n\n    public int GetHashCode(Client obj)\n    {\n        return obj.Email?.GetHashCode() ?? 0;\n    }\n}
\n\n

Verwendung:

\n
var comparer = new ClientEmailComparer();\nvar uniqueByEmail = clients.Distinct(comparer).ToList();
\n\n

Vorteile:

\n
    \n
  • Volle Kontrolle über die Vergleichslogik.
  • \n
  • Der Comparer kann in Contains, Except, Union usw. wiederverwendet werden.
  • \n
  • Erfordert keine externen Bibliotheken.
  • \n
\n\n

Nachteile:

\n
    \n
  • Viel Boilerplate-Code.
  • \n

Blogs

Buchempfehlungen