简体   繁体   中英

GroupBy in LINQ?

I'm working on the database application which shows clear report of the transaction by its tags.

This is my database .

Title      Amount       TagsReport (string[] array)
Food       5            "Hotel","Friends"
Food       6            "Hotel"
Family     8            "Hotel","Mobile"
Family     9            "Electricity"
Food       8            "Party"

I wish to generate the report like below:

Desired Output:

Percentage     Title             Amount
53%            Food              19
                  Hotel             11
                  Friends           5
                  Party             8

57%            Family            17
                 Hotel             8
                 Mobile            8
                 Electricity       9

I don't have enough knowledge on LINQ. So I face lot of trouble in this finding a perfect solution.

However I find this code to use,

var ReportingData = ReportListQuery
    .Where(Item => Item.Category == "expense")
    .GroupBy(item => item.Title)
    .Select(itemGroup => new
    {
        Percentage = Math.Round((itemGroup.Sum(item => item.Amount) / MonthExpense) * 100),
        ExpenseTitle = itemGroup.Key,
        ExpenseCalculation = itemGroup.Sum(item => item.Amount),
        TotalTagAmounts = itemGroup
        .SelectMany(item => item.TagsReport.Select(tag => new { 
            Tag = tag, 
            Amount = item.Amount 
        })
        .GroupBy(tagAmount => tagAmount.Tag)
        .Select(tagAmountGroup => new
        {
            Tag = tagAmountGroup.Key,
            TotalAmount = tagAmountGroup.Sum(tagAmount => tagAmount.Amount)
        }))
    });

And the output is like;

Percentage     Title                  Amount  
53%            Food                   19
                 Hotel                  5
                 Friends                5
                 Hotel                  6 //Hotel should be grouped here and should with the value 11 :-(
                 Party                  8

57%            Family                 17
                 Hotel                  8
                 Mobile                 8               
                 Electricity            9

But my desired output is:

Percentage     Title             Amount
53%            Food              19
                  Hotel             11
                  Friends           5
                  Party             8

57%            Family            17
                 Hotel             8
                 Mobile            8
                 Electricity       9

As you see, I made everything. But not the 'hotel' grouped in the reports. What am I doing wrong? Please advise!

I concur with Chris Cummings' observation regarding the misapplication of the grouping. Because you don't flatten (ie call SelectMany() on the TagsReport field until after you only have a single item, grouping the result winds up with just one group for each flattened sequence.

Based on your stated desired output, it seems that you really just have one misplaced closing parenthesis. You should write this instead:

var ReportingData = ReportListQuery
    .Where(Item => Item.Category == "expense")
    .GroupBy(item => item.Title)
    .Select(itemGroup => new
    {
        Percentage = Math.Round((itemGroup.Sum(item => item.Amount) / MonthExpense) * 100),
        ExpenseTitle = itemGroup.Key,
        ExpenseCalculation = itemGroup.Sum(item => item.Amount),
        TotalTagAmounts = itemGroup
        .SelectMany(item => item.TagsReport.Select(tag => new
        {
            Tag = tag,
            Amount = item.Amount
        })) // add parenthsis here
        .GroupBy(tagAmount => tagAmount.Tag)
        .Select(tagAmountGroup => new
        {
            Tag = tagAmountGroup.Key,
            TotalAmount = tagAmountGroup.Sum(tagAmount => tagAmount.Amount)
        }) // remove parenthesis here
    });

In other words: you want to group the whole flattened sequence of items within each "grouped-by-title" group, rather than flattening each individual item within each group. I simply removed the second ) on the next-to-the-last line, and added one just before the second GroupBy() call.

This produces exactly the output you describe. It's still odd (the sum of the individual tag amounts exceeds the total expense for each title group), but at least it's what you specifically asked for. :) (Well, not counting the percentages…given the example data, there's no way to have a single MonthExpense value for which the percentages add up, so I just didn't bother to try to make that number come out right).

It seems to me that your second group by is done per item, instead of over the tag group. So, you group by Title; say, Food. That group now has three items. "Hotel, Friends" - "Hotel" - "Party". Now, for EACH of those groups, you're doing a group by on tag. Well each group only has one of each. So it makes sense that you'd see Hotel, Friends, Hotel, Party. It seems to me you're not doing a group by on the whole set, you're doing a group by on each member of the set. You might want to store the original group to a variable, and then sum the results of that data set. Of course, only summing items with the same tags.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM