skip to Main Content

Would like to convert my current Angular reduce function below to calculate a moving average based on a period of every ~2-3 items. Is this possible to do w/ a standard Angular Reduce function?

This is what I currently have to compute a basic average, but would like to convert it to a moving average w/ a settable period if possible, but not sure how/if it’s possible to do w/ a standard Angular JS Reduce function.

const data = [
    { val: 20 },
    { val: 15 },
    { val: 10 },
    { val: 12 },
    { val: 15 },
    { val: 09 },
    { val: 14 },
    { val: 17 },
    { val: 11 },
    { val: 15 }
]

var avg = data.reduce((accum, curVal) => accum + curVal.val, 0) / data.length;
console.log("avg= " + avg);

2

Answers


  1. You can use the slice function to get a portion of the array

    let startIndex = 2;
    let endIndex = 5;
    let length = endIndex - startIndex;
    var avg= data.slice(startIndex , endIndex ).reduce((accum, curVal) => accum + curVal.val, 0) / length;
    console.log("avg= " + avg);
    
    Login or Signup to reply.
  2. If I’ve understood the question correctly you want an array with a set of averages based on a window that moves one entry at a time across the data. Here’s an example using a for loop, please see the comments for how this works:

    const data = [{ val: 20 }, { val: 15 }, { val: 10 }, { val: 12 }, { val: 15 }, { val: 9 }, { val: 14 }, { val: 17 }, { val: 11 }, { val: 15 }];
    
    const get_moving_averages = (data, window_size = 3) => {
      const sums = [];
      
      for(let i = 0; i < data.length; i++) {
        if(i < window_size) {
          // add everything to the first slot for the first items up to window size
          sums[0] = (sums[0] ?? 0) + data[i];
        } else {
          // calculate value by taking the previous value, adding the new data
          // and taking off value that shouldn't be included in this sum from the previous sum
          sums[i + 1 - window_size] = sums[i - window_size] + data[i] - data[i - window_size];
        }
      }
      
      return sums.map((sum) => sum / window_size);
    };
    
    console.log(get_moving_averages(data.map(({val}) => val)));

    Same idea but with a reduce function:

    const data = [{ val: 20 }, { val: 15 }, { val: 10 }, { val: 12 }, { val: 15 }, { val: 9 }, { val: 14 }, { val: 17 }, { val: 11 }, { val: 15 }];
    
    const get_moving_averages = (data, window_size = 3) =>
      data.reduce((acc, val, i, all) => {
        const first_few = i < window_size;
        const sum_index = first_few ? 0 : i + 1 - window_size;
        
        acc[sum_index] = (acc[sum_index] ?? 0) + val;
        
        if(!first_few)
          acc[sum_index] += acc[sum_index - 1] - all[i - window_size];
        
        return acc;
      }, [])
      .map( (sum) => sum / window_size );
    
    console.log(get_moving_averages(data.map(({val}) => val)));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search