Search code examples
linqlinq-group

linq query to group the items


var sales = _salesService.GetSales(parameters)

The list is something like

var listSales = new List<SalesData>();
listSales .Add(new SalesData
{
    Name = "Apple",
    Quantity = 1000
});
listSales .Add(new SalesData
{
    Name = "Banana",
    Quantity = 2000
});
listSales .Add(new SalesData
{
    Name = "Peach",
    Quantity = 1
});
listSales .Add(new SalesData
{
    Name = "Mango",
    Quantity = 1
});

I want to write a linq query so that I can group the 'Name' as 'Others' if the quantity is less than 1 percent of the total quantity.

So result of the query should be something like

Apple  56
Banana 23
Others 2  -- ( peach's quantity less than than 1% + Mango Quantity less than 1%)

Solution

  • Well, it sounds like first you need to know the total quantity. That's easy enough:

    var total = listSales.Sum(entry => entry.Quantity);
    

    Then you need to work out the cutoff point, which is 1% of it:

    var cutoff = total / 100;
    

    For the grouping and summing, I'd probably go in three steps:

    • Transform the original list into a sequence with entries of "Others"
    • Group entries by name
    • Sum per group

    So the overall code would be:

    var total = listSales.Sum(entry => entry.Quantity);
    // TODO: Work out whether you want the cutoff to be exclusive or not.
    var cutoff = total / 100;
    var results = listSales.Select(entry => entry.Quantity >= cutoff ?
                                                entry :
                                                new SalesData { 
                                                    Name = "Others",
                                                    Quantity = entry.Quantity
                                                })
                           .GroupBy(entry => entry.Name, entry => entry.Quantity)
                           .Select(group => new { Name = group.Key,
                                                  Total = group.Sum() });
    

    You can combine the "group and select" operations, but personally I find the above simpler to read.