168

I am trying to use .distinct in Linq to get result based on one field of the table (so do not require a whole duplicated records from table).

I know writing basic query using distinct as followed:

var query = (from r in table1
orderby r.Text
select r).distinct();

but I need results where r.text is not duplicated.

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
Megha Jain
  • 1,837
  • 2
  • 13
  • 8
  • You need to specify what field you want to be distinct ,see http://msdn.microsoft.com/en-us/library/bb348436.aspx – Antarr Byrd Jan 14 '13 at 15:10

10 Answers10

371

Try this:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());

This will group the table by Text and use the first row from each groups resulting in rows where Text is distinct.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • 2
    What if groupby has more than 1 field? –  Jan 06 '16 at 02:01
  • 18
    @user585440: In that case, you use an anonymous type like so: `table1.GroupBy(x => new { x.Text, x.Property2, x.Property3 }).Select(x => x.First());` – Daniel Hilgarth Jan 14 '16 at 12:58
  • 2
    Yes, you are right and I already found it. Thanks anyway. And I also find that Select(x => x.First()) can cause crash. It is better to change to Select(x => x.FirstOrDefault()); –  Jan 14 '16 at 21:24
  • 1
    @user585440: In that particular scenario, `First` will never cause an exception, because it takes the first item of each group. And there only is a group, if there is at least one item in it. – Daniel Hilgarth Jan 15 '16 at 05:30
  • 6
    I had to use FirstOrDefault or else there was a runtime error – TruthOf42 Apr 27 '16 at 16:02
  • 4
    @TruthOf42 That's rather unlikely. `GroupBy` doesn't create empty groups, see my previous comment. Most likely, your code contains more than what you see here. Maybe you have a `Where` as well or a condition for the `First`. – Daniel Hilgarth Apr 27 '16 at 16:04
  • @DanielHilgarth `FirstOrDefault` is mandatory if you are querying a database, even if the groups cannot be empty. – edc65 Oct 10 '16 at 09:10
  • @edc65 what makes you say that? – Daniel Hilgarth Oct 10 '16 at 09:44
  • My previuos experience makes me say that, but to be sure I tried with Linqpad using Linq To Entitities and framework 4.5. Is it perhaps different with 6.0? – edc65 Oct 10 '16 at 10:27
  • @edc65 maybe it was a special scenario where you had to use it in the past? – Daniel Hilgarth Oct 10 '16 at 13:36
  • @edc65 I may have misunderstood your previous comment. So you could verify in LinqPad that FirstOrDefault is not working? What is happening if you use it? – Daniel Hilgarth Oct 10 '16 at 13:59
  • (I can't go in chat, it's blocked by my firewall). I'm saying that `FirstOrDefault` **does work**. Instead you used `First` in your answer and `First` does not work and you get a runtime error `The method 'First' can only be used as a final query operation. Consider using the method 'FirstOrDefault' in this instance instead`. I can't be more clear than that. – edc65 Oct 10 '16 at 14:16
  • I'm curious under what circumstances we need to use *.FirstOrDefault()* instead of the unsafe *.First()*. If we're grouping by some key, isn't it already implied that no group can be empty? I'm figuring, if there's no elements corresponding to a certain key, then the key won't be in the set of keys of the grouping, will it? – Konrad Viltersten Apr 15 '21 at 15:23
  • @KonradViltersten: It seems to be or have been a limitation in Entity Framework. – Daniel Hilgarth Apr 19 '21 at 12:35
  • @DanielHilgarth Interesting. **Evil** me: "right, somone ducked up and blames EF". **Humble** me: "well, weirder things have happened...". I'm too lazy to try it out at the moment so I take your word for it. At any rate - strange that deafult suffix would be needed. Might have been some glitch in previous versions that I was lucky not to hit my toe on. – Konrad Viltersten Apr 20 '21 at 12:17
  • @KonradViltersten: Just read the other comments on this answer. It shows that I thought the same as you did – Daniel Hilgarth Apr 21 '21 at 13:41
39

MoreLinq has a DistinctBy method that you can use:

It will allow you to do:

var results = table1.DistictBy(row => row.Text);

The implementation of the method (short of argument validation) is as follows:

private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
    HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
    foreach (TSource element in source)
    {
        if (knownKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}
Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    sorry I wasnt keen to use equalityComparer. – Megha Jain Jan 14 '13 at 15:38
  • @MeghaJain Well, one will be used regardless, as `GroupBy` needs one as well. Both methods will use the default `EqualityComparer` if none is provided. – Servy Jan 14 '13 at 15:39
  • 9
    Well, correct me if I am wrong, but this distinct here is done in memory, not in DB ? Couldn't this lead to undesired full-scan ? – Kek Jan 14 '13 at 15:55
  • @Kek. No, because of the yield return, you will stop at the first distinct element. Eventually, yes, you will load each key into the HashSet, but since it's IEnumerable in and IEnumerable out, you will only get those items. If you are talking about LINQ to SQL, then yes, this will do a table scan. – PRMan May 11 '17 at 16:00
16

but I need results where r.text is not duplicated

Sounds as if you want this:

table1.GroupBy(x => x.Text)
      .Where(g => g.Count() == 1)
      .Select(g => g.First());

This will select rows where the Text is unique.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
13

Daniel Hilgarth's answer above leads to a System.NotSupported exception With Entity-Framework. With Entity-Framework, it has to be:

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());
Roshna Omer
  • 687
  • 1
  • 11
  • 20
Biraj Saha
  • 130
  • 1
  • 5
6

Update

As of .NET 6 a new DistinctBy operator has been introduced. However, while this works well for Linq to Objects, it doesn't appear to be working for Linq to Entities. I tested it with EF Core 6.0.6 and SQL server.

Generally speaking, LINQ operators come in pairs to support those two scenarios. For example, Enumerable.Select covers Linq to Objects, Queryable.Select covers Linq to Entities.

Interestingly DistinctBy has both of those flavors as well, but EF Core's SQL Server provider doesn't support it's translation to SQL. The reason, in my opinion, is that it would result in a slow query.

Original Answer

There are lots of discussions around this topic.

You can find one of them here:

One of the most popular suggestions have been the Distinct method taking a lambda expression as a parameter as @Servy has pointed out.

The chief architect of C#, Anders Hejlsberg has suggested the solution here. Also explaining why the framework design team decided not to add an overload of Distinct method which takes a lambda.

TKharaishvili
  • 1,997
  • 1
  • 19
  • 30
4

From what I have found, your query is mostly correct. Just change "select r" to "select r.Text" is all and that should solve the problem. This is how MSDN documented how it should work.

Ex:

    var query = (from r in table1 orderby r.Text select r.Text).distinct();
Josh Parks
  • 49
  • 3
1
data.Select(x=>x.Name).Distinct().Select(x => new SelectListItem { Text = x });
Pang
  • 9,564
  • 146
  • 81
  • 122
bgS
  • 219
  • 3
  • 5
0

Distinct return you SINGLE column, if that's your case then!!

CountryData.Select(x=>x.COUNTRY_NAME).Distinct()

Else if you need multiple columns distinct by one column. you need to groupby first then select the first item from the group. (in this case the rest items in group with different values will not be returned)

CountryData.GroupBy(a=>a.COUNTRY_NAME).Select(a=>a.First());
sami ullah
  • 925
  • 1
  • 9
  • 15
-2

try this code :

table1.GroupBy(x => x.Text).Select(x => x.FirstOrDefault());
HamidReza
  • 1,726
  • 20
  • 15
-6

You can try this:table1.GroupBy(t => t.Text).Select(shape => shape.r)).Distinct();

LucaGuerra
  • 319
  • 2
  • 11