2012-08-04 17 views
19

Mam list<message>, który zawiera właściwości typu Guid i DateTime (jak również inne właściwości). Chciałbym pozbyć się wszystkich pozycji z listy, gdzie Guid i DateTime są takie same (z wyjątkiem jednego). Nie będzie wtedy, gdy te dwie właściwości będą takie same jak innych elementów na liście, ale pozostałe właściwości będzie inna, więc nie można po prostu użyć .Distinct()Wybierz wyróżniony przez dwie właściwości na liście

List<Message> messages = GetList(); 
//The list now contains many objects, it is ordered by the DateTime property 

messages = from p in messages.Distinct( what goes here?); 

To co mam teraz, ale wydaje się, że powinien być lepszy sposób

List<Message> messages = GetList(); 

for(int i = 0; i < messages.Count() - 1) //use Messages.Count() -1 because the last one has nothing after it to compare to 
{ 
    if(messages[i].id == messages[i+1}.id && messages[i].date == message[i+1].date) 
    { 
     messages.RemoveAt(i+1); 
    { 
    else 
    { 
     i++ 
    } 
} 
+1

http://stackoverflow.com/questions/489258/linq-distinct-on-a-particular-property – Shyju

+0

dzięki. Nie wiem, dlaczego nie mogłem tego znaleźć, kiedy szukałem. – user1304444

+0

Cieszę się, że odpowiedź Jona dla ciebie zadziałała. Tylko uwaga: twoja "obecnie używana metoda" nie kompiluje się i (po naprawieniu błędów kompilacji) nie będzie działać we wszystkich przypadkach - w zależności od kolejności twoich elementów, dostaniesz różne ** (źle) ** wyniki (w końcu porównujesz tylko sąsiadujące ze sobą elementy). – Adam

Odpowiedz

52

LINQ to Objects nie przewiduje tej funkcji łatwo w wbudowanym w sposób, ale MoreLINQ posiada wygodny DistinctBy metody:

messages = messages.DistinctBy(m => new { m.id, m.date }).ToList(); 
+0

Zakładam, że MoreLINQ jest darmowy w użyciu? Nie widzę tego wyraźnie nigdzie na stronie. – user1304444

+2

@ user1304444: Jest to biblioteka typu open source - patrz link "Apache License 2.0" po lewej stronie. –

+3

Dla każdego, kto ogląda to pytanie, link wspomniany wyżej, Shyju, wydaje się również doskonałą odpowiedzią. http://stackoverflow.com/questions/489258/linq-distinct-on-a-particular-property – user1304444

2

Co z tym?

var messages = messages 
       .GroupBy(m => m.id) 
       .GroupBy(m => m.date) 
       .Select(m => m.First()); 
+0

nie kompiluje ... Pamiętaj, że GroupBy zwraca 'IGrouping'. – Adam

+0

To podejście jest prawidłowe, jeśli program HashSet nie jest dostępny w opracowywanej matrycy, takiej jak silverslight .... – Thomas

11

Jon Skeet na DistinctBy jest zdecydowanie do zrobienia, więc jeśli jesteś zainteresowany w określaniu własnego metodę rozszerzenia może wziąć nadzwyczajnego w tym bardziej zwięzłej wersji:

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

która ma ten sam podpis :

messages = messages.DistinctBy(x => new { x.id, x.date }).ToList(); 
+2

Wiem, że jest stary, ale zwróć uwagę, że musisz wywołać 'ToList()' lub 'ToArray()' po wywołaniu 'DistinctBy()'. Jeśli będziesz pracować bezpośrednio na 'IEnumerable' i wielokrotnie ją wyliczysz, to nie zadziała, ponieważ elementy zostaną dodane do' HashSet' podczas przechodzenia przez 'IEnumerable' za pierwszym razem i nie będą zwracane po raz drugi, jak pokazano w tym [.NET Fiddle] (https://dotnetfiddle.net/5PUJxl). – fknx

1

można sprawdzić moje PowerfulExtensions bibliotekę. Obecnie jest na bardzo młodym etapie, ale już możesz używać takich metod jak Distinct, Union, Intersect, Z wyjątkiem dowolnej liczby właściwości;

To jak go używać:

using PowerfulExtensions.Linq; 
... 
var distinct = myArray.Distinct(x => x.A, x => x.B);