296

I have a class list of class

public class LinqTest
{
public int id { get; set; }
public string value { get; set; }
}


List<LinqTest> myList = new List<LinqTest>();
myList.Add(new LinqTest() { id = 1, value = "a" });
myList.Add(new LinqTest() { id = 1, value = "b" });
myList.Add(new LinqTest() { id = 2, value = "c" });

I need to select only the distinct id's from that list. ie, my resultant list should only contain

[{id=1,value="a"},{ id = 2, value = "c" }]

How can I do this with linq?

Edit

Input,

id      value
1        a
1        b
2        c
3        d
3        e

Out put should be,

id      value
1        a
2        c
3        d

ie, if there is a repetition of id, result should take the first occurrence only.

2
  • 3
    Why should the result contain "a" instead of "b"? Commented Oct 16, 2013 at 14:39
  • 2
    @Jodrell : It should contain the first value. Commented Oct 16, 2013 at 14:48

4 Answers 4

597
myList.GroupBy(test => test.id)
      .Select(grp => grp.First());

Edit: as getting this IEnumerable<> into a List<> seems to be a mystery to many people, you can simply write:

var result = myList.GroupBy(test => test.id)
                   .Select(grp => grp.First())
                   .ToList();

But one is often better off working with the IEnumerable rather than IList as the Linq above is lazily evaluated: it doesn't actually do all of the work until the enumerable is iterated. When you call ToList it actually walks the entire enumerable forcing all of the work to be done up front. (And may take a little while if your enumerable is infinitely long.)

The flipside to this advice is that each time you enumerate such an IEnumerable the work to evaluate it has to be done afresh. So you need to decide for each case whether it is better to work with the lazily evaluated IEnumerable or to realize it into a List, Set, Dictionary or whatnot.

Sign up to request clarification or add additional context in comments.

6 Comments

FYI: This won't work unless you convert it back to a list again. GroupBy().Select(First()) will generate an ienumerable and you'll get a conversion error. Do this: myList.GroupBy(test => test.id) .Select(group => group.First()).ToList();
And you have to define newList. Then Set result to this newList. Otherwise grouping does not work. This worked for me. 'List<LinqTest> newList = new List<LinqTest>(); newList = myList.GroupBy(test => test.id) .Select(group => group.First());'
Hey yunus. Thanks for your little comment. I was able to get my IEnumerable to work by using your code and changing List stuff: IEnumerable<EDI_RAW_TCR> rows = from c in dc.EDI_RAW_TCRs where c.Batch_ID == 20830 select c; IEnumerable<EDI_RAW_TCR> raws = rows; raws = rows.GroupBy(t => t.LabID) .Select(group => group.First());
in C# it require .FirstOrDefault() instead of .First()
@Sruit, C# doesn't require this, but you EF may give you some headache if you try to do this, say, in the repository.
|
144

Using morelinq you can use DistinctBy:

myList.DistinctBy(x => x.id);

Otherwise, you can use a group:

myList.GroupBy(x => x.id)
      .Select(g => g.First());

3 Comments

Didnt know about this package absolutely what was needed good man
Which is faster?
@MarkWardell: DistinctBy never existed in .NET. As I wrote in my answer, you need to use morelinq to get that functionality
63

You should override Equals and GetHashCode meaningfully, in this case to compare the ID:

public class LinqTest
{
    public int id { get; set; }
    public string value { get; set; }

    public override bool Equals(object obj)
    {
        LinqTest obj2 = obj as LinqTest;
        if (obj2 == null) return false;
        return id == obj2.id;
    }

    public override int GetHashCode()
    {
        return id;
    }
}

Now you can use Distinct:

List<LinqTest> uniqueIDs = myList.Distinct().ToList();

Comments

31
myList.GroupBy(i => i.id).Select(group => group.First())

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.