1

I need to display a cumulative sum in a list using lambda expressions. Do you have any idea how I can do it? I have this return:

[
{
    "dt_created": "2018-02-25",
    "qtNewItens": 1
},
{
    "dt_created": "2018-02-26",
    "qtNewItens": 1
},
{
    "dt_created": "2018-02-27",
    "qtNewItens": 2
}

]

But i have to display this:

[
{
    "dt_created": "2018-02-25",
    "qtNewItens": 1
},
{
    "dt_created": "2018-02-26",
    "qtNewItens": 2
},
{
    "dt_created": "2018-02-27",
    "qtNewItens": 4
}

]

I don´t know if can do using GroupBy or Aggregate

I try something like this, but its wrong:

var newItensByDay = ctx.Itens
                    .GroupBy(x => new { Data = x.dt_created, x.Id })
                    .Select(g => new {
                        Qt = g.Select(x => x.Id).Count(),
                        Dt_created = g.Select(x => x.dt_created).FirstOrDefault()
                    })
                    .GroupBy(x => new { x.Qt, x.Dt_created })
                    .Select(grp => new {
                        dt_created = grp.Key.Dt_created,
                        qtNewItens = grp.Sum(x => x.Qt)
                    });
Userssp
  • 43
  • 5

3 Answers3

1

Consider the following cumulative select after the grouping

var itemsByDay = ctx.Itens
                    .GroupBy(x => x.dt_created)
                    .Select(g => new {
                        Qt = g.Count(),
                        Dt_created = g.Key
                    });

var count = 0;
var cumulativeByDay = itemsByDay.Select(x => {
    count += x.Qt;
    var result = new {
        dt_created = x.Dt_created,
        qtNewItens = count
    };
    return result;
});
Nkosi
  • 235,767
  • 35
  • 427
  • 472
1

This should do what you want:

var runningTotal = 0;
dataList.Select(x=>new Data(){dt_created = x.dt_created, qtNewItems = (runningTotal+=x.qtNewItems)}).Dump();

Essentially it delcares a variable to use as the runningTotal and then in the projection it uses runningTotal+=x.qtNewItems to add the value to the running total and then assigns that to the new object.

Chris
  • 27,210
  • 6
  • 71
  • 92
1

If you would like the client code to be one expression you can make a generic AccumulatingSelect iterator and use it like this:

source.AccumulatingSelect (
    0, 
    (s, a) => s.qtNewItens + a, 
    (s, a) => new { s.dt_created, TotalToDate = a })

.

public static class Extensions {
    public static IEnumerable<V> AccumulatingSelect<T, U, V>(
      this IEnumerable<T> source, 
      U seed, 
      Func<T, U, U> accumulator, 
      Func<T, U, V> projector)
    {
        U acc = seed;
        foreach (var value in source)
        {
            acc = accumulator(value, acc);
            yield return projector(value, acc);
        }
    }
}

Which is an overdressed version of what @Chris gave.

Tom Blodget
  • 20,260
  • 3
  • 39
  • 72