Home > OS >  Aggregate values from array of JSON objects based on timestamp
Aggregate values from array of JSON objects based on timestamp

Time:09-17

I am relatively new to programming and javascript and i want to achieve the following. Let's assume that we have the following data:

let data =
  [
    {
      "time": 1663163352001,
      "state": "10"
    },
    {
      "time": 1663163352002,
      "state": "20"
    },
    {
      "time": 1663163354002,
      "state": "10"
    },
    {
      "time": 1663163354002,
      "state": "10"
    },
    {
      "time": 1663163355033,
      "state": "30"
    },
    {
      "time": 1663163355035,
      "state": "10"
    },
    {
      "time": 1663163397035,
      "state": "30"
    },
    {
      "time": 1663163397044,
      "state": "50"
    }

  ]

i want to aggregate and calculate the averaged state based on timestamps on time interval (let's say 1 second) so the output should be

let data =
  [
    {
      "time": 1663163352000,
      "state": "15"
    },
    {
      "time": 1663163353000,
      "state": "0"
    },
    {
      "time": 1663163354000,
      "state": "10"
    },
    {
      "time": 1663163355000,
      "state": "20"
    },
    {
      "time": 1663163356000,
      "state": "0"
    },
    {
      "time": 1663163397000,
      "state": "40"
    }

  ]

I know my code is not right but at this is the logic that i have already implement.

//Inputs
var t_interval = 1000;


let aggregatedValues = [];
let count = 0;
let sum = 0;
//starting point converted in seconds
t0 = data[0].time - data[0].time % 1000;
//the timewindow
t_win = t0   t_interval;

//Just for this case 
for (let i = 0; i < 7; i  ) {

  if ( data[i].time < t_win) {
    count  = 1;
    sum  = parseFloat(data[i].state);
  } 
  else{
    if (sum === 0 || count === 0) {
      avg = NaN;
    }
    avg = sum / count;
    count = 1;
    sum = parseFloat(data[i].state);

    let temp = {
      "time": t_win - t_interval,
      "state": avg
    }
    aggregatedValues.push(temp);
    t_win = t_win   t_interval;
  }
  
}

Could you help me please? Thank you!

CodePudding user response:

Pretty simple task, reduce over your collection to create an object with key = timestamp and value = object of total amount of states and count of met items. Apply some rounding operation on timestamp. Then 1 more loop to calculate average values. Convert it back to array and sort (if needed). Gaps filling is up to you.

const data = [
  { time: 1663163352001, state: "10" },
  { time: 1663163352002, state: "20" },
  { time: 1663163354002, state: "10" },
  { time: 1663163354002, state: "10" },
  { time: 1663163355033, state: "30" },
  { time: 1663163355035, state: "10" },
  { time: 1663163397035, state: "30" },
  { time: 1663163397044, state: "50" }
];

function aggregate(items) {
  const step = 1000 * 1; // 1 second

  const resObj = items.reduce((acc, item) => {
    const roundedTimestamp = Math.round(item.time / step) * step;
    const parsedValue = parseInt(item.state, 10);

    const existing = acc[roundedTimestamp];
    if (!existing) {
      acc[roundedTimestamp] = {
        count: 1,
        value: parsedValue
      };
    } else {
      existing.count  = 1;
      existing.value  = parsedValue;
    }

    return acc;
  }, {});

  const res = Object.entries(resObj)
    .map(([key, value]) => ({
      time: parseInt(key, 10),
      value: (value.value / value.count).toString()
    }))
    .sort((a, b) => a.time - b.time);

  // fill gaps if you really need that.
  //

  return res;
}

console.log(aggregate(data));

  • Related