简体   繁体   中英

Linq to return list with calculated sums based on property

I have a list of invoices which all have an entryDate as datetime and amount as double. I need to return a list of doubles with the last 12 months of turnover, so I get a list like 19486.23, 52742.19, 23653.79 and so on for all 12 months. Is that possible?

    public async Task<IEnumerable<Double>> GetTurnoverYear()
    {
        var invoices = await GetInvoices();
        var turnover = invoices.???
    }

    public async Task<IEnumerable<Bill>> GetInvoices()
    {
        var client = new HttpBase();
        using (var httpClient = client.GetBaseClient())
        {
            var response = await httpClient.GetAsync("invoices");
            var result = await response.Content.ReadAsStringAsync();
            dynamic data = JsonConvert.DeserializeObject<dynamic>(result);
            var invoices = JsonConvert.DeserializeObject<IEnumerable<Invoice>>(data.invoices.ToString());
            return invoices;
        }
    }

create a variable for a date that is 12 months ago and do a Where

var list = new List<Invoice> {
new Invoice{entryDate=new DateTime(2019,1,1),amount=2},
new Invoice{entryDate=new DateTime(2019,1,1),amount=2},
new Invoice{entryDate=new DateTime(2020,6,1),amount=1},
new Invoice{entryDate=new DateTime(2020,7,1),amount=1}
};

var aYearAgo = DateTime.Today.AddMonths(-12);
var last12Months = list.Where(l => l.entryDate > aYearAgo).Select(l => l.amount);

//or 
var last12Months = list.Where(l => l.entryDate > DateTime.Today.AddMonths(-12)).Select(l => l.amount);
//this will work the same but its less readable i think

Assuming you don't want to start the last 12 months somewhere in the middle of a month, so we'll first have to calculate the first day of the month 12 months ago:

DateTime now = DateTime.Now;
DateTime firstDayThisMonth = new DateTime(now.Year, now.Month, 1);
var firstDayOfMonthOneYearAgo = firstDayThisMonth.AddMonths(-12);

We want to get rid of all with an EntryDate older than the first day of the month one year ago:

var newerInvoices = dbContext.Invoices
    .Where(invoice => invoice.EntryDate >= firstDayOfMonthOneYearAgo)

Make groups of invoices with the same month. We don't want to group the invoices of this month with the invoices of the month one year ago (june 2020 not together with june 2019). So the GroupBy must be on year and month:

// parameter keySelector: make groups with same Year / Month as EntryDate:
.GroupBy(invoice => new
{
    Year = invoice.EntryDate.Year,
    Month = invoice.EntryDate.Month}

// Parameter resultSelector: take each year/month combination and all invoices with this
// year/month combination to calculate the sum of all Amounts in the group:
(yearMonth, invoicesInThisYearMonth) => new
{
    Year = yearMonth.Year,
    Month = yearMonth.Month,
    Total = invoicesInThisYearMont.Select(invoice => invoice.Amount).Sum(),
});

Note: one year ago you will have the complete month (july 2019), but for july 2020, you'll only have the sum of the Amounts until today (2020-07-20)

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