class Program
{
static void Main(string[] args)
{
List<Book> books = new List<Book>
{
new Book
{
Name="C# in Depth",
Authors = new List<Author>
{
new Author
{
FirstName = "Jon", LastName="Skeet"
},
new Author
{
FirstName = "Jon", LastName="Skeet"
},
}
},
new Book
{
Name="LINQ in Action",
Authors = new List<Author>
{
new Author
{
FirstName = "Fabrice", LastName="Marguerie"
},
new Author
{
FirstName = "Steve", LastName="Eichert"
},
new Author
{
FirstName = "Jim", LastName="Wooley"
},
}
},
};
var temp = books.SelectMany(book => book.Authors).Distinct();
foreach (var author in temp)
{
Console.WriteLine(author.FirstName + " " + author.LastName);
}
Console.Read();
}
}
public class Book
{
public string Name { get; set; }
public List<Author> Authors { get; set; }
}
public class Author
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override bool Equals(object obj)
{
return true;
//if (obj.GetType() != typeof(Author)) return false;
//else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;
}
}
Dies basiert auf einem Beispiel in "LINQ in Action". Listing 4.16.
Dies druckt Jon Skeet zweimal. Warum? Ich habe sogar versucht, die Equals-Methode in der Author-Klasse zu überschreiben. Trotzdem scheint Distinct nicht zu funktionieren. Was vermisse ich?
Edit: Ich habe auch == und! = Operatorüberladung hinzugefügt. Immer noch keine Hilfe.
public static bool operator ==(Author a, Author b)
{
return true;
}
public static bool operator !=(Author a, Author b)
{
return false;
}
quelle
IEquatable
(und überschriebenEquals
/GetHashCode
), aber keiner meiner Haltepunkte wird in diesen Methoden auf einem Linq ausgelöstDistinct
.GetHashCode
undEquals
sie wurden während der foreach-Schleife getroffen. Dies liegt daran, dass dievar temp = books.SelectMany(book => book.Authors).Distinct();
Rückgabe an erfolgtIEnumerable
, was bedeutet, dass die Anforderung nicht sofort ausgeführt wird, sondern nur, wenn die Daten verwendet werden. Wenn Sie sofort ein Beispiel für dieses Brennen wünschen, fügen Sie es.ToList()
nach dem hinzu,.Distinct()
und Sie sehen die Haltepunkte imEquals
undGetHashCode
vor dem foreach.Die
Distinct()
Methode überprüft die Referenzgleichheit auf Referenztypen. Dies bedeutet, dass buchstäblich dasselbe Objekt dupliziert wird, nicht verschiedene Objekte, die dieselben Werte enthalten.Es gibt eine Überladung, die einen IEqualityComparer erfordert , sodass Sie eine andere Logik angeben können, um zu bestimmen, ob ein bestimmtes Objekt einem anderen entspricht.
Wenn Sie möchten, dass sich der Autor normalerweise wie ein normales Objekt verhält (dh nur die Referenzgleichheit), aber zum Zwecke der eindeutigen Überprüfung der Gleichheit anhand von Namenswerten einen IEqualityComparer verwenden . Wenn Sie immer möchten, dass Author-Objekte basierend auf den Namenswerten verglichen werden, überschreiben Sie GetHashCode und Equals oder implementieren Sie IEquatable .
Die beiden Mitglieder der
IEqualityComparer
Benutzeroberfläche sindEquals
undGetHashCode
. Ihre Logik zum Bestimmen, ob zweiAuthor
Objekte gleich sind, scheint zu sein, wenn die Vor- und Nachnamenzeichenfolgen gleich sind.quelle
Eine weitere Lösung ohne Umsetzung
IEquatable
,Equals
undGetHashCode
ist die LINQs zu verwendenGroupBy
Methode und das erste Element aus der IGrouping auszuwählen.quelle
.GroupBy(y => new { y.FirstName, y.LastName })
Es gibt noch eine Möglichkeit, eindeutige Werte aus der Liste der benutzerdefinierten Datentypen abzurufen:
Sicherlich wird es unterschiedliche Daten geben
quelle
Distinct()
führt den Standardgleichheitsvergleich für Objekte in der Aufzählung durch. Wenn Sie nicht außer Kraft gesetzt habenEquals()
undGetHashCode()
dann verwendet er die Standardimplementierung aufobject
, die Referenzen vergleicht.Die einfache Lösung besteht darin , allen Klassen, die an dem zu vergleichenden Objektdiagramm beteiligt sind (z. B. Buch und Autor) , eine korrekte Implementierung von
Equals()
und hinzuzufügenGetHashCode()
.Die
IEqualityComparer
Schnittstelle ist eine Bequemlichkeit , die Sie implementieren könnenEquals()
undGetHashCode()
in einer separaten Klasse , wenn Sie haben keinen Zugriff auf die Interna der Klassen , die Sie vergleichen müssen, oder wenn Sie eine andere Methode des Vergleichs verwendet wird .quelle
Sie haben Equals () überschrieben, aber stellen Sie sicher, dass Sie auch GetHashCode () überschreiben.
quelle
<custom>^base.GetHashCode()
Die obigen Antworten sind falsch !!! Distinct wie in MSDN angegeben gibt den Standardäquator zurück, der wie angegeben Die Default-Eigenschaft prüft, ob Typ T die System.IEquatable-Schnittstelle implementiert, und gibt in diesem Fall einen EqualityComparer zurück, der diese Implementierung verwendet. Andernfalls wird ein EqualityComparer zurückgegeben, der die von T bereitgestellten Überschreibungen von Object.Equals und Object.GetHashCode verwendet
Was bedeutet, solange Sie Equals überschreiben, geht es Ihnen gut.
Der Grund, warum Ihr Code nicht funktioniert, ist, dass Sie Vorname == Nachname überprüfen.
Siehe https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx und https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx
quelle
Sie können die Erweiterungsmethode für Listen verwenden, die die Eindeutigkeit basierend auf dem berechneten Hash überprüft. Sie können die Erweiterungsmethode auch ändern, um IEnumerable zu unterstützen.
Beispiel:
Verlängerungsmethode:
quelle
Sie können dies auf zwei Arten erreichen:
1. Sie können die IEquatable-Schnittstelle wie in der Enumerable.Distinct-Methode gezeigt implementieren, oder Sie können die Antwort von @ skalb in diesem Beitrag sehen
2. Wenn Ihr Objekt keinen eindeutigen Schlüssel hat, können Sie die GroupBy-Methode verwenden, um eine eindeutige Objektliste zu erhalten. Sie müssen alle Eigenschaften des Objekts gruppieren und nach Auswahl des ersten Objekts.
Zum Beispiel wie unten und für mich arbeiten:
Die MyObject-Klasse sieht wie folgt aus:
3. Wenn Ihr Objekt einen eindeutigen Schlüssel hat, können Sie ihn nur in Gruppe nach verwenden.
Zum Beispiel ist der eindeutige Schlüssel meines Objekts Id.
quelle