Blank Blank
Blank Blank

Reputation: 61

How to get distinct mutiple columns with a simple linq?

I have a List of products such as :

List<Product> products = new List<Product>();
products.Add( new Product{ ProductID=1,Category="Food",SubCategory="Snacks",Location="Tokyo"});

products.Add( new Product{ ProductID=1,Category="Food",SubCategory="Snacks",Location="Tokyo"});

products.Add( new Product{ ProductID=1,Category="Food",SubCategory="Snacks",Location="Tokyo"});

I need a simple query to find distinct records for products. I was doing something like:

products.Select(x=>x.ProductID||x=>x.Category||x=>x.SubCategory).Distinct().ToList();

Upvotes: 0

Views: 68

Answers (2)

kuldeep
kuldeep

Reputation: 865

You need to update your product class by providing overrides for Equals and == != operators. Also provide the implementation for GetHashCode. Please note that a good GetHashCode implementation is necessary/suggested as equal items would return equal hashes.

SO has some good discussion on that here

Regardless product class should look something like this

public class Product
{
    public int ProductID { get; internal set; }
    public string Category { get; internal set; }
    public string SubCategory { get; internal set; }
    public string Location { get; internal set; }

    public override bool Equals(Object obj)
    {
        //Check for null and compare run-time types.
        if ((obj == null) || !this.GetType().Equals(obj.GetType()))
        {
            return false;
        }
        else
        {
            Product p = (Product)obj;
            return (ProductID == p.ProductID) &&
                (Category == p.Category) &&
                (Location == p.Location) &&
                (SubCategory == p.SubCategory)
                ;
        }
    }

    public static bool operator ==(Product b1, Product b2)
    {
        if (b1 is null)
            return b2 is null;

        return b1.Equals(b2);
    }

    public static bool operator !=(Product b1, Product b2)
    {
        return !(b1 == b2);
    }

    public override int GetHashCode()
    {
        //https://learn.microsoft.com/en-us/archive/blogs/ericlippert/guidelines-and-rules-for-gethashcode
        return ProductID;
    }


}

And then in your LINQ

products.Select(x => x).Distinct().ToList();

Hope this helps !

Upvotes: 2

Joe Mayo
Joe Mayo

Reputation: 7513

The Distinct operator has an overload that takes an IEqualityComparer<T>, so you could change Product to implement that:

class Product : IEqualityComparer<Product>
{
    public int ProductID { get; internal set; }
    public string Category { get; internal set; }
    public string SubCategory { get; internal set; }
    public string Location { get; internal set; }

    public bool Equals(Product x, Product y)
    {
        return
            x.Category.Equals(y.Category) &&
            x.Location.Equals(y.Location) &&
            x.SubCategory.Equals(y.SubCategory);
    }

    public int GetHashCode(Product obj)
    {
        return ProductID;
    }
}

Then your query could work like this:

var distinctProducts =
    (from product in products
     select product)
    .Distinct(new Product())
    .ToList();

Notice that I passed an instance of Product, which implements IEqualityComparer<Product> to Distinct.

Upvotes: 3

Related Questions