Reputation: 9476
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
.
Upvotes: 88
Views: 152980
Reputation: 857
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())
Upvotes: 7
Reputation: 9077
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();
Upvotes: 0
Reputation: 3964
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();
Upvotes: 7
Reputation: 1499800
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.)
Upvotes: 86
Reputation: 1233
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();
Upvotes: 23
Reputation: 6152
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());
Upvotes: 27
Reputation: 108790
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());
Upvotes: 165