views:

239

answers:

2

I'm trying to create a LINQ query (or queries) that count the total number of occurences of a combinations of items in one list that exist in a different list. For example, take the following lists:

CartItems                  DiscountItems
=========                  =============
AAA                        AAA
AAA                        BBB
AAA
BBB
BBB
CCC
CCC
DDD

The result of the query operation should be 2 since I can find two combinations of AAA and BBB (from DiscountItems) within the contents of CartItems.

My thinking in approaching the query is to join the lists together to shorten CartItems to only include items from DiscountItems. The solution would be to find the CartItem in the resulting query that occurs the least amount of times, thus indicating how many combinations of items exist in CartItems.

When CartItems is filtered to only the items in DiscountItems, it can be visually displayed like this:

CartItems that get a discount
=============================
AAA    BBB    <=   This combination is eligible for a discount
AAA    BBB    <=   This combination is eligible for a discount
AAA           <=   Not eligible

Thus, because there are 2 combinations of the discount in the Cart, the result is 2.

How can this be done?


Here's the query I already have, but it's not working. query results in an enumeration with 100 items, far more than I expected.

    Dim query = From cartItem In Cart.CartItems
                Group Join discountItem
                    In DiscountGroup.DiscountItems
                    On cartItem.SKU Equals discountItem.SKU
                    Into Group
                Select SKU = cartItem.SKU, CartItems = Group

    Return query.Min(Function(x) x.CartItems.Sum(Function(y) y.Quantity))
+2  A: 

I think what you want is the size of the set intersection based on your description.

return Cart.CartItems.Intersect( DiscountGroup.DiscountItems ).Count()

This assumes that the items are really the same things (and they are comparable). If not, then you'd need to select out just the keys that you use to compare them and do an intersection on the keys.

 return Cart.CartItems.Select( Function(c) c.SKU )
                      .Intersect( DiscountGroup.DiscountItems
                                               .Select( Function(d) d.SKU  )
                      .Count()
tvanfosson
@tvan I may have been unclear in my original question and have since edited it for clarification. The intersection does in fact show items that exist in both sets, but it only shows them *once*. I need to the number of times that all the items in the set `DiscountItems` appear in the set `CartItems`.
Ben McCormack
So basically what you want is to count the number of times you can remove the tuple represented in the discount list from the cart items? I think that @Mark's answer will work for that since that's basically the minimum number of occurrences in CartItems of each item in Discount Items.
tvanfosson
+1  A: 

If I understand your question correctly you want this:

int count = DiscountItems.Min(x => CartItems.Count(item => item == x));

Result:

2

This assumes that DiscountItems cannot contain duplicates. If it can and you want a duplicate to mean that the item must appear in the cart twice to count as one discount then use this code instead:

int count = DiscountItems
    .GroupBy(d => d)
    .Min(x => CartItems.Count(item => item == x.Key) / x.Count());

I just noticed that you wanted an answer in VB.NET. I imagine that you are more easily able to translate this to VB.NET than I can as my VB.NET is not so great, but if not then leave a message and I will try running it through .NET Reflector to see if it can translate it automatically to something readable.

Mark Byers
@Mark Thanks for the answer. I generally prefer to code in C#, but I have to use VB.NET for work. I can translate that when I go to test it. An immediate difference I noticed between C# and VB.NET when it comes to LINQ is how lambda's are expressed. Instead of `(item => item == x.Key)`, you have `(function(item) (item = x.Key))`.
Ben McCormack