1

I have a list of Filters that are passed into a webservice and I iterate over the collection and do Linq query and then add to the list of products but when I do a GroupBy and Distinct() it doesn't remove the duplicates. I am using a IEnumerable because when you use Disinct it converts it to IEnumerable. If you know how to construct this better and make my function return a type of List<Product> that would be appreciated thanks.

Here is my code in C#:

if (Tab == "All-Items")
{
    List<Product> temp = new List<Product>();
    List<Product> Products2 = new List<Product>();
    foreach (Filter filter in Filters)
    {                        
        List<Product> products = (from p in db.Products where p.Discontinued == false
                                  && p.DepartmentId == qDepartment.Id
                                  join f in db.Filters on p.Id equals f.ProductId
                                  join x in db.ProductImages on p.Id equals x.ProductId
                                  where x.Dimension == "180X180"
                                  && f.Name == filter.Name /*Filter*/
                                  select new Product
                                  {
                                      Id = p.Id,
                                      Title = p.Title,
                                      ShortDescription = p.ShortDescription,
                                      Brand = p.Brand,
                                      Model = p.Model,
                                      Image = x.Path,
                                      FriendlyUrl = p.FriendlyUrl,
                                      SellPrice = p.SellPrice,
                                      DiscountPercentage = p.DiscountPercentage,
                                      Votes = p.Votes,
                                      TotalRating = p.TotalRating
                                  }).ToList<Product>();

        foreach (Product p in products)
        {
            temp.Add(p);
        }                        

        IEnumerable temp2 = temp.GroupBy(x => x.Id).Distinct();
        IEnumerator e = temp.GetEnumerator();
        while (e.MoveNext()) {
            Product c = e.Current as Product;
            Products2.Add(c);
        }
    }
    pf.Products = Products2;// return type must be List<Product>                
}
dthorpe
  • 35,318
  • 5
  • 75
  • 119
ONYX
  • 5,679
  • 15
  • 83
  • 146
  • I see you are using ToList earlier in your code - you can use it on your return value too. – sq33G Nov 18 '11 at 02:37

3 Answers3

4

You need to override Equals and GetHashCode to compare Products by value.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
3

You're assigning the GroupBy result to temp2, but then you never use it!

IEnumerable temp2 = temp.GroupBy(x => x.Id).Distinct();         
IEnumerator e = temp.GetEnumerator();   // <- why temp and not temp2???

But you aren't really using the GroupBy operator properly at all. You need to group and then select an item from each group, not select the distinct groups. The groups are already distinct.

When you group by the Id, you'll actually return a structure like this

-Key: 1
   -Product (Id = 1)
-Key: 2
   -Product (Id = 2)
   -Product (Id = 2)

You need to retrieve an item from each group. Assuming the are duplicates, you won't care which item you get so you can just take the first item from each group.

var groups = temp.GroupBy(x => x.Id);
var distinctItems = groups.Select(g => g.First());

foreach (var item in distinctItems)
{
    // do stuff with item
    Products2.Add(item);
}
Kirk Broadhurst
  • 27,836
  • 16
  • 104
  • 169
  • ...why are you still calling Distinct? – sq33G Nov 18 '11 at 02:42
  • @sq33G good pickup ;) purely because I cut & pasted the original code and forgot to remove it. Fixed now. – Kirk Broadhurst Nov 18 '11 at 02:48
  • I tried you're example and it didn't work and this part here Product c = e.Current as Product; doesn't exist in the context any other suggestions – ONYX Nov 18 '11 at 02:58
  • My mistake it works thanks heaps I learned something new today cheers by the way my name is Kirk aswell! – ONYX Nov 18 '11 at 03:04
0

SLaks is right, you have to override the Equals() and GetHashCode() methods to accomplish this.

Here is how I did it within an Order object in small program I wrote. Hope this helps!

    //overridden Equals() method from the Object class, determines equality based on order number
    public override bool Equals(object obj)
    {
        bool equal;
        if (this.GetType() != obj.GetType())
            equal = false;
        else
        {
            Order temp = (Order)obj;
            if(OrderNumber == temp.OrderNumber)
                equal = true;
            else
                equal = false;
        }
        return equal;
    }

    //overridden GetHashCode() method from Object class, sets the unquie identifier to OrderNumber
    public override int GetHashCode()
    {
        return OrderNumber;
    }
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
jmshapland
  • 483
  • 4
  • 10
  • when you say object class is that for my class Product or my webservice im confused where to put it – ONYX Nov 18 '11 at 02:18
  • and what do i need to change in my code that I provided can you update what I put up – ONYX Nov 18 '11 at 02:20
  • You want to do it in your Product class since that is what you are trying to compare. – jmshapland Nov 18 '11 at 02:20
  • Just add something similar to the code I posted within your Product class. I'm assuming ID is your unique identifier for your products so just replace OrderNumber with ID and it should work. – jmshapland Nov 18 '11 at 02:24
  • and the code I provided that does the Distinct and Enumerator part is that code ok or does that need to change – ONYX Nov 18 '11 at 02:25