Frage LINQs Distinct () für eine bestimmte Eigenschaft


Ich spiele mit LINQ, um etwas darüber zu lernen, aber ich kann nicht herausfinden, wie man Distinct benutzt, wenn ich keine einfache Liste habe (eine einfache Liste von Ganzzahlen ist ziemlich einfach zu machen, das ist nicht die Frage). Was ich möchte verwenden Eindeutig auf einer Liste eines Objekts auf ein oder Mehr Eigenschaften des Objekts?

Beispiel: Wenn ein Objekt ist Personmit Eigenschaft Id. Wie kann ich alle Personen bekommen und benutzen? Distinct auf sie mit dem Eigentum Id des Objekts?

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

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

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


775
2018-01-28 20:45


Ursprung


Antworten:


BEARBEITEN: Dies ist jetzt ein Teil von MehrLINQ.

Was Sie brauchen, ist ein "distinct-by" effektiv. Ich glaube nicht, dass es Teil von LINQ ist, 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;
        }
    }
}

So finden Sie die eindeutigen Werte mit nur der Id Eigenschaft, könnten Sie verwenden:

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

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 jetzt zumindest kompiliert).

Es wird jedoch der Standardvergleich für die Schlüssel vorausgesetzt - wenn Sie einen Gleichheitsvergleich übergeben möchten, übergeben Sie ihn einfach an den HashSet Konstrukteur.


925
2018-01-28 21:17



Was, wenn ich eine eindeutige Liste basierend auf erhalten möchte ein oder Mehr Eigenschaften?

Einfach! Sie möchten 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 folgendermaßen vor:

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

1456
2018-01-29 14:39



Sie können die Abfragesyntax auch verwenden, wenn Sie möchten, dass sie vollständig LINQ-ähnlich 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();

61
2018-03-06 18:28



Ich denke, es ist genug:

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

47
2018-01-23 14:54



Benutzen:

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

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

Das where hilft Ihnen, die Einträge zu filtern (könnte komplexer sein) und die groupby und select Führen Sie die eindeutige Funktion aus.


36
2018-02-14 12:52



Sie können dies mit dem Standard tun Linq.ToLookup(). Dies erstellt eine Sammlung von Werten für jeden eindeutigen Schlüssel. Wählen Sie einfach das erste Objekt in der Sammlung aus

Persons.ToLookup(p => p.Id).Select(coll => coll.First());

18
2018-01-20 15:01



Der folgende Code entspricht funktional Jon Skeets Antwort.

Getestet auf .NET 4.5, sollte mit jeder früheren Version von LINQ funktionieren.

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

Übrigens, check out Jon Skeets neueste Version von DistinctBy.cs in Google Code.


15
2018-02-06 19:56



Lösung zuerst Gruppe von Ihren Feldern dann wählen Sie zuerst oder Standard-Element.

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

14
2017-07-13 08:33