Uzyskaj listę różnych wartości na liście

175

W C # powiedz, że mam klasę o nazwie Note z trzema zmiennymi składowymi typu String.

public class Note
{
    public string Title;
    public string Author;
    public string Text;
}

I mam listę typu Uwaga:

List<Note> Notes = new List<Note>();

Jaki byłby najczystszy sposób uzyskania listy wszystkich odrębnych wartości w kolumnie Autor?

Mógłbym iterować listę i dodać wszystkie wartości, które nie są duplikatami, do innej listy ciągów, ale wydaje się to brudne i nieefektywne. Mam wrażenie, że istnieje jakaś magiczna konstrukcja Linq, która zrobi to w jednej linii, ale nie byłem w stanie niczego wymyślić.

Darrel Hoffman
źródło

Odpowiedzi:

331
Notes.Select(x => x.Author).Distinct();

To zwróci sekwencję ( IEnumerable<string>) Authorwartości - po jednej na unikalną wartość.

Kirk Woll
źródło
1
Notes.Select (x => x.Author) .AsParallel (). Distinct (); „AsParallel ()” może przynieść pewne korzyści w zakresie wydajności, jeśli nie zależy nam na kolejności i mamy więcej elementów na liście.
Sai
1
@Kiquenet, odrębne, biorąc pod uwagę funkcję porównującą Defaultrówność. msdn.microsoft.com/en-us/library/bb348436(v=vs.110).aspx
Georg Patscheider
Czy musimy dodać ToList () przed .Distinct ()?
Phan Đức Bình
1
Nie przed Distinct (), ale po, jeśli próbujesz przekonwertować na listę. Np .: Notes.Select (x => x.Author) .Distinct (). ToList ();
MTwiford
87

Wyróżnij klasę Note według autora

var DistinctItems = Note.GroupBy(x => x.Author).Select(y => y.First());

foreach(var item in DistinctItems)
{
    //Add to other List
}
atik sarker
źródło
1
Czy nie powinno to być Notestak samo Notes.GroupBy()z liczbą mnogą, sjak Notebędzie zawierać tylko jedną nutę?
kkuilla
30

Jon Skeet napisał bibliotekę o nazwie morelinq, która ma DistinctBy()operatora. Zobacz tutaj implementację. Twój kod będzie wyglądał

IEnumerable<Note> distinctNotes = Notes.DistinctBy(note => note.Author);

Aktualizacja: Po ponownym przeczytaniu pytania Kirk ma poprawną odpowiedź, jeśli szukasz tylko odrębnego zestawu autorów.

Dodano próbkę, kilka pól w DistinctBy:

res = res.DistinctBy(i => i.Name).DistinctBy(i => i.ProductId).ToList();
Dan Busha
źródło
Wspaniale, dziękuję. Podoba mi się to, że zachowuje właściwą kolejność, jeśli uporządkuję listę przed wywołaniem metody Distinct.
Vilhelm
Zaktualizowałem linki. LINQ jest teraz na Github i można go zainstalować przez Nuget:Install-Package morelinq
Chad Levy,
2
public class KeyNote
{
    public long KeyNoteId { get; set; }
    public long CourseId { get; set; }
    public string CourseName { get; set; }
    public string Note { get; set; }
    public DateTime CreatedDate { get; set; }
}

public List<KeyNote> KeyNotes { get; set; }
public List<RefCourse> GetCourses { get; set; }    

List<RefCourse> courses = KeyNotes.Select(x => new RefCourse { CourseId = x.CourseId, Name = x.CourseName }).Distinct().ToList();

Korzystając z powyższej logiki, możemy uzyskać unikalne Courses.

Bhaskar
źródło
Twój Distinct przed ToList oszczędza mój czas .. Robię po ToList i podaje błąd, który nie może przekonwertować listy na Ienumerable.
Ajay2707
Odrębność nie zadziała tutaj, ponieważ dla tego operatora każdy obiekt jest unikalny na podstawie kodu skrótu obiektu. Potrzebujesz czegoś podobnego do tego - github.com/morelinq/MoreLINQ/blob/master/MoreLinq/DistinctBy.cs
Bose_geek
-2
mcilist = (from mci in mcilist select mci).Distinct().ToList();
ravinderreddy Seeelam
źródło
Czym właściwie jest mci? Tylko przykładowy stół? Odpowiedź jest trochę niezręczna.
Brad Koch
1
Tak, nie sądzę, żeby to spełniało moje pierwotne pytanie (nieważne, że było to półtora roku temu, a projekt już dawno się skończył). Z tego, co wiem, zadziałałoby to, gdybym miał już listę ciągów znaków Autora, które mogą zawierać duplikaty, ale nie można ich użyć do wyodrębnienia takiej listy z listy obiektów, których jednym z pól jest ciąg znaków Autor.
Darrel Hoffman