130
class obj
{
    int typeId; //10 types  0-9 
    string uniqueString; //this is unique
}

Assume there is a list with 100 elements of objs, but only 10 unique typeIDs.

Is it possible to write a LINQ query that returns the 10 unique ints from the list of objs?

0

7 Answers 7

224
objList.Select(o=>o.typeId).Distinct()
Sign up to request clarification or add additional context in comments.

3 Comments

The second form seems to use an overload of Distinct which doesn't exist as far as I'm aware.
Oops, removed the second one, thanks @Jon Skeet, that can be done with IEqualityComparer
As Jon Skeet mentioned, this will only return the properties specified in the Select.
84

Assuming you want the full object, but only want to deal with distinctness by typeID, there's nothing built into LINQ to make this easy. (If you just want the typeID values, it's easy - project to that with Select and then use the normal Distinct call.)

In MoreLINQ we have the DistinctBy operator which you could use:

var distinct = list.DistinctBy(x => x.typeID);

This only works for LINQ to Objects though.

You can use a grouping or a lookup, it's just somewhat annoying and inefficient:

var distinct = list.GroupBy(x => x.typeID, (key, group) => group.First());

5 Comments

To have DistinctBy to appear you need to add the namespace Microsoft.Ajax.Utilities
@Shil: No, I was writing about the DistinctBy in MoreLINQ. Nothing to do with Microsoft.Ajax.Utilities.
Now I can see there is an overload of Distinct in LINQ which take an IEqualityComparer as parameter and return a list of distinct objects depending upon the implementation of methods in IEqualityComparer
@DipenduPaul: Yes, but that still means creating an equality comparer for a given property, which is annoying and makes it harder to read. If you can take the MoreLINQ dependency, I think that's cleaner.
Since .NET 6, DistinctBy is now included in System.Linq. learn.microsoft.com/en-us/dotnet/api/…
58
+200

If just want to user pure Linq, you can use groupby:

List<obj> distinct =
  objs.GroupBy(car => car.typeID).Select(g => g.First()).ToList();

If you want a method to be used all across the app, similar to what MoreLinq does:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (!seenKeys.Contains(keySelector(element)))
        {
            seenKeys.Add(keySelector(element));
            yield return element;
        }
    }
}

Using this method to find the distinct values using just the Id property, you could use:

var query = objs.DistinctBy(p => p.TypeId);

you can use multiple properties:

var query = objs.DistinctBy(p => new { p.TypeId, p.Name });

2 Comments

Thanks for the multiple properties part!
.NET 6 now has the distinctBy extension method. Documentation
7

Sure, use Enumerable.Distinct.

Given a collection of obj (e.g. foo), you'd do something like this:

var distinctTypeIDs = foo.Select(x => x.typeID).Distinct();

Comments

5

I think this is what your looking for:

    var objs= (from c in List_Objects 
orderby c.TypeID  select c).GroupBy(g=>g.TypeID).Select(x=>x.FirstOrDefault());      

Similar to this Returning a Distinct IQueryable with LINQ?

2 Comments

.First is fine, since you wouldn't have the group if there wasn't something in it.
You can use an alternative overload of GroupBy to make this simpler too - see my answer for an example.
5

If just want to use Linq, you can override Equals and GetHashCode methods.

Product class:

public class Product
{
    public string ProductName { get; set; }
    public int Id { get; set; }


    public override bool Equals(object obj)
    {
        if (!(obj is Product))
        {
            return false;
        }

        var other = (Product)obj;
        return Id == other.Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

Main Method:

static void Main(string[] args)
    {

        var products = new List<Product>
        {
            new Product{ ProductName="Product 1",Id = 1},
            new Product{ ProductName="Product 2",Id = 2},
            new Product{ ProductName="Product 4",Id = 5},
            new Product{ ProductName="Product 3",Id = 3},
            new Product{ ProductName="Product 4",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
        };

        var itemsDistinctByProductName = products.Distinct().ToList();

        foreach (var product in itemsDistinctByProductName)
        {
            Console.WriteLine($"Product Id : {product.Id} ProductName : {product.ProductName} ");
        }

        Console.ReadKey();
    }

1 Comment

This only makes sense for a class where equality is completely determined by the property you wish to query! I recommend using any other answer instead.
3

I wanted to bind a particular data to dropdown and it should be distinct. I did the following:

List<ClassDetails> classDetails;
List<string> classDetailsData = classDetails.Select(dt => dt.Data).Distinct.ToList();
ddlData.DataSource = classDetailsData;
ddlData.Databind();

See if it helps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.