user1304444
user1304444

Reputation: 1753

Select distinct by two properties in a list

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++
    }
}

Upvotes: 55

Views: 62247

Answers (5)

Manish Agarwal
Manish Agarwal

Reputation: 21

Try this,

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

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1499860

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

Upvotes: 127

Andrzej Gis
Andrzej Gis

Reputation: 14306

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

Upvotes: 1

Adam
Adam

Reputation: 15805

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

Upvotes: 22

Andrew Church
Andrew Church

Reputation: 1391

What about this?

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

Upvotes: 0

Related Questions