0

I have the following class:

public class TotalPaymentStatistics 
{ 
     public DateTime RegisteredAt { get; set; }
     public double TotalAmount { get; set; }  
}

Also I have following examplary data stored in database:

2021-01-01 | 120
2021-01-02 | 120
2021-01-03 | 120
2021-01-04 | 120
2021-01-05 | 120
2021-01-06 | 120
2021-01-07 | 120
2021-01-08 | 120
2021-01-09 | 120
2021-01-10 | 120

How to group object of this class in such a way, that when I pass argument, for example 5, (5 - being a time frame, meaning that I want to received sumarized data for every 5 days period in the whole set), I will receive following results:

2021-01-01 600
2021-01-05 600

Thanks in advance

mSwierkot
  • 35
  • 7

4 Answers4

0

you can try this. suppose your dbcontext class is _context and add DaysCount as int type to model for days count, then you can write as

_context.yourTables.GroupBy(x=>x.RegisteredAt.Date).select(t=>new TotalPaymentStatistics (){
 RegisteredAt =t.Key,
 TotalAmount =t.Sum(s=>s.TotalAmount),
 DaysCount = t.Count()
}).ToList();
0

Universal approach would be to just use rounding to nearest. You can specify any time interval that way. For example:

Rounding DateTime objects

Then you can just:

var groupInterval = TimeSpan.FromDays(5);
var groups = input
      .GroupBy(x=> x.RegisteredAt.Floor(groupInterval))
      .Select(x=> 
          new 
          { 
               date = x.Key, 
               sum = x.Sum(y=> y.TotalAmount)
          });

You can tweak with it a little to get desired groups by specifying starting shift or using Floor/Ceiling/Round methods.

eocron
  • 6,885
  • 1
  • 21
  • 50
0

With a naive partitioning: data is ordered, and has at least one element.

static IEnumerable<List<T>> Partition<T>(List<T> input, Func<T, DateTime> DateSelector, TimeSpan partitionSize)
{
    var partitionEnd = DateSelector(input.First()).Add(partitionSize);
    var partition = new List<T>();

    foreach (var element in input)
    {
        var dt = DateSelector(element);
        if (dt >= partitionEnd)
        {
            yield return partition;
            partition = new List<T>();
            partitionEnd = dt.Add(partitionSize);
        }
        partition.Add(element);
    }
    yield return partition;
}

You can do

var result = Partition(input, (x) => x.Date, TimeSpan.FromDays(partitionSize))
                .Select(p => new { Date = p.Min(x=> x.Date), Amount = p.Sum(x => x.Amount) });

Live demo https://dotnetfiddle.net/lpwgbI

Result:

Date Amount
01/01/2021 00:00:00 600
01/06/2021 00:00:00 600
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Self
  • 349
  • 1
  • 8
0
<pre>
void Main()
{
    var items = new List<TotalPaymentStatistics>()
    {
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,1),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,2),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,3),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,4),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,5),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,6),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,7),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,8),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,9),TotalAmount = 120},
        new TotalPaymentStatistics(){RegisteredAt = new DateTime(2021,1,10),TotalAmount = 120},
    };
    DateTime day0 = items[0].RegisteredAt.AddDays(-1);
    var q = items
        .GroupBy(x => ((int)((x.RegisteredAt.Subtract(day0).TotalDays-1) / 5)))
        .Select(x => new {
            x.Key,
            Date = day0.AddDays(x.Key*5+1),
            Amount = x.Sum(y => y.TotalAmount)
        });
    foreach(var item in q)
    {
        Console.WriteLine($"{item.Date.ToString("yyyy-MM-dd")} {item.Amount}");
    }
}

// Define other methods and classes here
public class TotalPaymentStatistics
{
    public DateTime RegisteredAt { get; set; }
    public double TotalAmount { get; set; }
}
</pre>

which will give you :

2021-01-01 600

2021-01-06 600

MarcG
  • 322
  • 1
  • 7