Raaz Raaz - 3 months ago 8
C# Question

How to populate a dictionary from another with same keys but values cumulated

I am looking for a help in solving an exercise using C#, LINQ.

I have a dictionary with

DateTime
as key and a
decimal
as value. I am trying to write a method that returns another dictionary with a value that is sum of all values of previous months and current month within that year. For the next year, the process repeats.

Input dictionary:

01/31/2015 100
02/28/2015 100
03/31/2015 100
;
; and so on
;
01/31/2017 200
02/28/2017 200
03/31/2017 200


Output should be as below:

01/31/2015 100
02/28/2015 200
03/31/2015 300
;
;
01/31/2017 200
02/28/2017 400
03/31/2017 600


Here is what I did so far. It computes the total but not resetting for the next year. In Jan 2016, it adds the value of Jan to the previous sum. I guess a GroupBy is needed before I write aggregate().

public static IDictionary<DateTime, decimal?> RunningTotal_NotResettingForNextYear(this IDictionary<DateTime, decimal?> inputDictionary)
{

IDictionary<DateTime, decimal?> runningTotalDictinary =
new Dictionary<DateTime, decimal?>(inputDictionary.Count);
inputDictionary.Aggregate((decimal?)0, (sum, value) =>
{
sum = sum + value.Value;
runningTotalDictinary.Add(value.Key, sum);
return sum;
});

return runningTotalDictinary;
}

Answer

The missing part is GroupBy method.

  • First, group inputDictionary by year.
  • Then compute the new value for each item with an accumulator (F# inspired) group by group
  • Merge groups into one liste.
  • Create the new dictionary.

Then the final code :

var newDico = inputDictionary.OrderBy(i => i.Key).GroupBy(i => i.Key.Year).SelectMany(
    group =>
        {
            decimal? accumulator = 0;
            return
            group.Select(
                element =>
                    new { Key = element.Key, Value = (accumulator += element.Value)});
        }).ToDictionary(accGroupItem => accGroupItem.Key, accGroupItem => accGroupItem.Value);

Or with a temp accumulator dictionary :

var dicoAcc = inputDictionary
                  .Select(i => i.Key.Year)
                  .Distinct()
                  .ToDictionary(year => year, _ => (decimal?)0);

var newDico = inputDictionary
                  .ToDictionary(i => i.Key, i => dicoAcc[i.Key.Year] += i.Value);
Comments