78

I have a List<MyClass> someList.

class MyClass
{
    public int Prop1...
    public int Prop2...
    public int Prop3...
}

I would like to know how to get a new distinct List<MyClass> distinctList from List<MyClass> someList, but only comparing it to Prop2.

Willem
  • 9,166
  • 17
  • 68
  • 92
  • duplicate: http://stackoverflow.com/questions/489258/linq-distinct-on-a-particular-property – Luis Feb 14 '11 at 11:50

7 Answers7

157

You can emulate the effect of DistinctBy using GroupBy and then just using the first entry in each group. Might be a bit slower that the other implementations though.

someList.GroupBy(elem=>elem.Prop2).Select(group=>group.First());
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • 25
    Also works with multiple properties: `someList.GroupBy(elem=> new { elem.Prop1, elem.Prop2, elem.Prop3 }).Select(group=>group.First());` – RJB Jun 25 '15 at 17:25
  • 4
    This should have been accepted answer. It does not depend on any external libraries and clean – Tejasvi Hegde Feb 08 '17 at 15:19
  • 1
    @TejasviHegde: Well, it has downsides compared with using `DistinctBy` as well: 1) it takes more memory, as it builds a group for every element; 2) it can't stream the results - it has to completely read `someList` before it yields any elements. I would say the MoreLINQ approach is cleaner. – Jon Skeet May 08 '17 at 06:57
  • 1
    @JonSkeet Thanks! I didn't think from this angle :) Btw. I just went through the code of your library, I loved the coding style and neat implementation! – Tejasvi Hegde May 08 '17 at 11:37
  • This really helped me a lot. we can also add .ToList() at the end. btw really helpful – Mubashar Shahzad Aug 20 '18 at 15:49
  • This really helped me a lot. – Aԃιƚყα Gυɾαʋ Aug 18 '23 at 20:03
77

Unfortunately there's no really easy built-in support for this in the framework - but you can use the DistinctBy implementation I have in MoreLINQ.

You'd use:

var distinctList = someList.DistinctBy(x => x.Prop2).ToList();

(You can take just the DistinctBy implementation. If you'd rather use a Microsoft implementation, I believe there's something similar in the System.Interactive assembly of Reactive Extensions.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    @Jon, does it really worth to use MoreLINQ for such things instead of implementing `IEqualityComparer` for `IEnumerable.Distinct`? – zerkms Feb 14 '11 at 11:47
  • @zerkms: Personally I would use MoreLINQ or Reactive Extensions, yes... it really doesn't take much effort to include it, and the calling code ends up being more readable IMO. – Jon Skeet Feb 14 '11 at 11:49
  • 1
    @Jon, I just worry about adding dependencies on 3rd party code. In other hand - built in solution obliges us to write bloated code... :-S – zerkms Feb 14 '11 at 11:51
  • @Jon do you happen to know why they didn't add an overload to Distinct that takes a lambda? Same question for the overload of Contains. – Stilgar Feb 14 '11 at 11:53
  • DistinctBy is nice, but what if i want to implement more complex logic, like 2 fields? – Ilya Smagin Feb 14 '11 at 11:54
  • 7
    @Ilya: That's easy: `foo.DistinctBy(x => new { x.Prop1, x.Prop2 });` – Jon Skeet Feb 14 '11 at 11:55
  • @Stilgar: I don't know... there are various additional features which would be *nice* to have in LINQ. Of course they'd then have to be implemented in LINQ to SQL etc as well... – Jon Skeet Feb 14 '11 at 11:56
  • @Jon, thanks. @zerkms: if you do not want to reference 3rd party code, write it yourself. it's pretty much easy to do. – Ilya Smagin Feb 14 '11 at 12:08
  • OMG, this is so... so... Satisfying. Thanks! – MarceloBarbosa Apr 04 '17 at 19:50
  • @TejasviHegde: It would be helpful if in future you could just suggest the relevant edit to be approved... – Jon Skeet May 09 '17 at 11:55
  • @JonSkeet Sorry, I some how I couldn't look at edit option :) – Tejasvi Hegde May 09 '17 at 13:24
  • epic, no need to actually use morelinq, just implement their distinctby – WtFudgE Mar 26 '19 at 04:17
26

you need to use .Distinct(..); extension method. Here's a quick sample:

public class Comparer : IEqualityComparer<Point>
    {
        public bool Equals(Point x, Point y)
        {
            return x.X == y.X;
        }

        public int GetHashCode(Point obj)
        {
            return (int)obj.X;
        }
    }

Do not forget about GetHashCode.

Usage:

List<Point> p = new List<Point>();
// add items
p.Distinct(new Comparer());
Ilya Smagin
  • 5,992
  • 11
  • 40
  • 57
  • 2
    What should be happened if we call `p.Distinct();` without `new Comparer()` parameter? In general `ListOfObjects.Distinct()` how works? – Iman Mahmoudinasab Feb 09 '14 at 16:19
  • @ImanMahmoudinasab, in general, .NET will use equality methods(Equals and GetHashCode) from the object. If they are not defined, they would be compared by reference, therefore, an object would be equal to itself only. – Ilya Smagin Jun 18 '15 at 08:04
  • How can we use Distinict , without writing " new Comparer() " as @ImanMahmoudinasab said ? – Parsa Feb 18 '17 at 11:54
  • @Parsa writing distinct without comparer is easy `p.Distinct();`. Distinct without comparer is usefull only when you want to check two _instance_ is same referane (same memory) not equal (diferent memory but equal property value). – Iman Mahmoudinasab Feb 19 '17 at 06:19
  • @Parsa Example: `var a=new Person("Iman"); var b=new Person("Iman"); var pList=new List(); pList.Add(a); pList.Add(b); pList.Add(a);` in this example `pList` contains `a` twice and using `pList.Distinc()` will give you just **one** `a` and one `b`. Notice that both `a` and `b` has equal name: `Iman`. So `pList.Distinc().Count()` is **2**. but with a comparer `pList.Distinc(new NameComparer()).Count()` is **1**. – Iman Mahmoudinasab Feb 19 '17 at 06:22
  • This is awesome! I love this solution – Samy Sammour Feb 12 '19 at 14:36
22

Override Equals(object obj) and GetHashCode() methods:

class MyClass
{
    public int Prop1 { get; set; }
    public int Prop2 { get; set; }
    public int Prop3 { get; set; }

    public override bool Equals(object obj)
    {
        return ((MyClass)obj).Prop2 == Prop2;
    }
    public override int GetHashCode()
    {
        return Prop2.GetHashCode();
    }
}

and then just call:

List<MyClass> distinctList = someList.Distinct().ToList();
Waldemar Gałęzinowski
  • 1,125
  • 1
  • 10
  • 18
6

Since the introduction of value tuples, if you want a LINQ equivalent to SQL's DISTINCT

items.GroupBy(item => (item.prop1, item.prop2, ...)).Select(group => group.First())
hngr18
  • 817
  • 10
  • 13
4

If you would like to Distinct your list by multiple fields, You have to create an instance of IEqualityComparer interface:

public class MyComparer : IEqualityComparer<MyModel>
{
    public bool Equals(MyModel x, MyModel y)
    {
       // compare multiple fields
        return
            x.Field1 == y.Field1 &&
            x.Field2 == y.Field2 &&
            x.Field3 == y.Field3 ;
    }

    public int GetHashCode(MyModel obj)
    {
        return 
            obj.Field1.GetHashCode() + 
            obj.Field2.GetHashCode() + 
            obj.Field3.GetHashCode();
    }
}

Then use the comparer to distinct your list:

var distinctedList = myList.Distinct(new MyComparer()).ToList();
Masoud Darvishian
  • 3,754
  • 4
  • 33
  • 41
0

I know it's been a while, but I needed the simplest answer and at this time (with .NET 4.5.1) I found the following to be the most straight-forward answer I could get to:

IEnumerable<long> allIds = waitingFiles.Values.Select(wf => wf.groupId).Distinct();

My situation is that I have a ConcurrentDictionary that looks something like: ConcurrentDictionary<long, FileModel>

The ConcurrentDictionary Values property is basically my List<FileModel>.

*FileModel has a groupId that isn't necessarily unique (though, obviously the key (long) that I use to add the FileModel object into the dictionary is unique to the FileModel).

*Named for clarity in the example.

The point is that I have a large number of FileModels (imagine 100) in the ConcurrentDictionary and within those 100 FileModels there are 5 different groupIds.

At this point I just need a list of the distinct groupId.

So, again if I just had a list of FileModel the code would look like the following:

IEnumerable <long> allIds = allFileModel.Select(fm => fm.groupId).Distinct();
Waldemar Gałęzinowski
  • 1,125
  • 1
  • 10
  • 18
raddevus
  • 8,142
  • 7
  • 66
  • 87