skip to Main Content

Is there a better way to calculate a moving sum of a list?

List<double?> rollingSum({int window = 3, List data = const []}) {
  List<double?> sum = [];

  int i = 0;
  int maxLength = data.length - window + 1;

  while (i < maxLength) {
    List tmpData = data.getRange(i, i + window).toList();
    double tmpSum = tmpData.reduce((a, b) => a + b);
    sum.add(tmpSum);
    i++;
  }

  // filling the first n values with null
  i = 0;
  while (i < window - 1) {
    sum.insert(0, null);
    i++;
  }

  return sum;
}

2

Answers


  1. Well, the code is already clean for what you need. Maybe just some improvements like:

    • Use a for loop
    • You can use the method sublist which creates a "view" of a list, which is more efficient
    • To insert some values in the left/right of a list, there is a specific Dart method called padLeft, where you specify the lenght of the list which you want it to become (first parameter), then the value you want to use to fill it (second parameter). For example, if you have an array of N elements, and you want to fill it with X "null"s to the left, use padLeft(N+X, null).
    List<double?> rollingSum({int window = 3, List data = const []}) {
      List<double?> sum = [];
    
      for (int i = 0; i < data.length - window + 1; i++) {
        List tmpData = data.sublist(i, i + window);
        double tmpSum = tmpData.reduce((a, b) => a + b);
        sum.add(tmpSum);
      }
    
      sum.padLeft(window - 1, null);
      return sum;
    }
    
    Login or Signup to reply.
  2. if I understand your problem correctly you can just calculate the window one time and in one loop you can for each iteration you can add the current element to the sum and subtract i - (window - 1)

    so for an input like this

    data = [1,2,3,4,5,6]

    window = 3

    the below code will result in [6,9,12,15]

    int sum = 0;
    List<double> res = [];
    for (int i = 0;i<data.length;i++) {
         sum += data[i];
         if (i < window - 1) {
             continue;
         }
         res.add(sum);
         sum -= data[i - (window - 1)]; // remove element that got out of the window size
     }
         
    

    this way you won’t have to use getRange nor sublist nor reduce as all of those are expensive functions in terms of time and space complexity

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search