Wednesday, February 15, 2012

LINQ: way to remove duplicate items in the collection

A few days ago I was faced with the need to remove duplicate items from the collection. And I found several ways to solve this problem.
So imagine we have a database table, which looks like this:
ActAccessKeyId AccessKey Date ClientId
1 jqtgtvmuvllp5nnc 2011-10-31 1
2 yq2wdbodatnyf597 2011-10-31 2
3 q9wpe8okgmedai7e 2011-10-31 2
4 hywbk3kzwdyexzoi 2011-10-31 2
5 eizpyjjggyfrdtvi 2011-10-31 2
6 28xd3phopswiwhqs 2011-10-31 3
7 vddew7ci7uyvxufi 2011-10-31 4
8 vk8nzhx98vsczzz8 2011-10-31 4
9 cn398xqfwjxyhyqs 2011-10-31 4
10 nikvc6bsb8dlc27e 2011-10-31 4
11 nhugfwdvydaoybqd 2011-10-31 5

This table stores keys, which can be used to fetch acts for different clients. All acts stored in database and for one client there can be more than one act. But i needed to receive a collection with a single act for each client. Basically, it means that i needed to remove records with duplicated ClientId’s and keep one unique records for each client. Let’s assume that database table mapped to a class:
public class ActAccessKey
    {
        public long ActAccessKeyId { get; set; }
        public string AccessKey { get; set; }
        public long ClientId { get; set; }
        public DateTime Date { get; set; }
    }
And we already have list of all records called actAccessKeys. The obvious way to solve this problem is to use custom comparer:
public class ActCustomDistinctComparer: IEqualityComparer<actaccesskey>
        {
            public bool Equals(ActAccessKey x, ActAccessKey y)
            {
                return x.ClientId == y.ClientId;
            }

            public int GetHashCode(ActAccessKey obj)
            {
                return obj.ClientId.GetHashCode();
            }
        }
This custom comparer could be used like this:
var distinctKeys = actAccessKeys.Distinct(new ActCustomDistinctComparer());
And as a result we get the following collection:
ActAccessKeyId AccessKey Date ClientId
1jqtgtvmuvllp5nnc2011-10-311
2yq2wdbodatnyf5972011-10-312
628xd3phopswiwhqs2011-10-313
7vddew7ci7uyvxufi2011-10-314
11nhugfwdvydaoybqd2011-10-315

The other way is more interesting and with only LINQ involved:
var distinctKeys = actAccessKeys.GroupBy(g => g.ClientId).Select(actKeys => actKeys.First());
Here we group our collection by ClientId in order to have a collection which consists of collections of objects with a common key. Basically, the type of the collection returned by GroupBy() method will be like this:
IEnumerable<IGrouping<long, ActAccessKey>>
and after that we take first element out of each group.

No comments :

Post a Comment