I have a list of Invoices and all the Products on each Invoice. Each Invoice can have multiples of the same product
class InvoiceProducts
{
public int InvoiceID { get; set; }
public int ProductID { get; set; }
}
var list = new List<InvoiceProducts>();
list.Add(new { InvoiceID = 7000, ProductID=15});
list.Add(new { InvoiceID = 7000, ProductID=10});
list.Add(new { InvoiceID = 7000, ProductID=10});
list.Add(new { InvoiceID = 7000, ProductID=15});
list.Add(new { InvoiceID = 7010, ProductID=12});
list.Add(new { InvoiceID = 7010, ProductID=20});
list.Add(new { InvoiceID = 7010, ProductID=12});
list.Add(new { InvoiceID = 7021, ProductID=1});
list.Add(new { InvoiceID = 7021, ProductID=1});
Can I please ask assistance in grouping per InvoiceID, and having a (Sorted) integer list of unique Products per invoice (The reason for sorting is that I need to match this with other invoices with the same products later)
i.e.
InvoiceID ProductID
7000 10,15
7010 12,20
7021 1
Failed attempts:
var tl2 = List
.GroupBy(x => x.InvoiceID)
.ToDictionary(y => y.Key, y => y.Distinct().ToList());
Failed Attempt explained : it has a dictionary which grouped correctly by InvoiceID, but invoice 7000 had 4 line items instead of 2 unique products
You want ToLookup
here - it's designed for precisely this scenario.
var lookup = list.ToLookup(x => x.InvoiceID, x => x.ProductID);
That will still contain the duplicate product IDs, but you can easily make them distinct when you fetch them:
var products = list[7000].Distinct();
Or you could just use Distinct()
on your list:
var lookup = list.Distinct()
.ToLookup(x => x.InvoiceID, x => x.ProductID);
That would work with the code using the anonymous type, but not if you actually use your InvoiceProducts
type. You could always project:
var lookup = list.Select(x => new { x.InvoiceID, x.ProductID })
.Distinct()
.ToLookup(x => x.InvoiceID, x => x.ProductID);
... or just make your InvoiceProducts
type implement equality appropriately.
See more on this question at Stackoverflow