57

I have a list<message> that contains properties of type Guid and DateTime (as well as other properties). I would like to get rid of all of the items in that list where the Guid and DateTime are the same (except one). There will be times when those two properties will be the same as other items in the list, but the other properties will be different, so I can't just use .Distinct()

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? ); 

This is what I have right now, but it seems like there ought to be a better way

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++ } } 
5
  • 2
    stackoverflow.com/questions/489258/… Commented Aug 4, 2012 at 18:39
  • Thanks. I don't know why I couldn't find that when I searched. Commented Aug 4, 2012 at 19:34
  • I'm glad Jon's answer worked for you. Just a note of caution: your "currently used method" doesn't compile, and (after fixing the compile errors) it will not work in all cases - depending on the order of your elements, you'd get different (wrong) results (after all, you're only comparing adjacent elements with each other). Commented Aug 4, 2012 at 19:59
  • thanks for the heads-up. GetList() returns an ordered List. I've tested different cases, and I get the result I need. Commented Aug 6, 2012 at 15:35
  • Possible duplicate of LINQ's Distinct() on a particular property Commented Jul 22, 2018 at 15:29

5 Answers 5

130

LINQ to Objects doesn't provide this functionality easily in a built-in way, but MoreLINQ has a handy DistinctBy method:

messages = messages.DistinctBy(m => new { m.id, m.date }).ToList(); 
Sign up to request clarification or add additional context in comments.

10 Comments

@user1304444: It's an open source library - see the "Apache License 2.0" link on the left of the page.
For anyone else viewing this question, the link Shyju mentioned above seems to be a great answer also. stackoverflow.com/questions/489258/…
@user1304444: Yeah, I think it was around the time of writing that answer that I decided to start MoreLINQ :)
@PaulZahra: Together. Two items a and b will only be seen as equal if a.id == b.id && a.date == b.date.
This is now available in .NET 6 without needing a third-party dependency or custom extension method!
|
22

Jon Skeet's DistinctBy is definitely the way to go, however if you are interested in defining your own extension method you might take fancy in this more concise version:

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))); } 

which has the same signature:

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

1 Comment

I know this is old, but please note that you have to call ToList() or ToArray() after calling DistinctBy(). If you work directly on the IEnumerable and enumerate it multiple times it won't work, since the items are added to the HashSet while going through the IEnumerable the first time and won't be returned a second time, as shown in this .NET Fiddle.
2

Try this,

 var messages = (from g1 in messages.GroupBy(s => s.id) from g2 in g1.GroupBy(s => s.date) select g2.First()).ToList(); 

Comments

1

You can check out my PowerfulExtensions library. Currently it's in a very young stage, but already you can use methods like Distinct, Union, Intersect, Except on any number of properties;

This is how you use it:

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

Comments

0

What about this?

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

2 Comments

does not compile... Remember that GroupBy returns an IGrouping.
This approach is valid if HashSet<T> is not available on the plateform you are developing like silverslight ....

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.