Le Rilleur
Le Rilleur

Reputation: 245

Returning an object with the average of the properties which have the same hour timestamp

I have an array of object that looks like that:

[{
  TIMESTAMP: "2021-05-07 03:32:00.0",
  PM2_5: "27.4",
  PM10: "67.9",
  CO: "0.058",
},
{
  TIMESTAMP: "2021-05-07 03:42:00.0",
  PM2_5: "27.0",
  PM10: "67.3",
  CO: "0.026",
},
{
  TIMESTAMP: "2021-05-07 04:08:00.0",
  PM2_5: "27.0",
  PM10: "67.3",
  CO: "0.066",
}
...]

There's more data ofc. I want to do a function that will take my array as a parameter and return an array of object. In this return array I want to merge all the object with the same hour timestamp together and do an average off all of their properties. I don't know which property they will have and the number can vary. So that I can have one object for each hour. For example for all the object at 3h, I will have

{
  TIMESTAMP: "2021-05-07 03:00:00.0",
  PM2_5: "27.2",
  PM10: "67.3",
  CO: "0.046",
}

For the 3h range I will have the average of all the data resume in one object.And I want to do this for all the hours I can have in the array. I tried to use reduce, or do a big loop, but my problem is that I don't want to precise the key in my loop I want it to work for all the keys that can exist.

function getAverage(datas) {
 const res = []
 datas.forEach((data, i) => {
  if (moment.tz(data.TIMESTAMP, 'YYYY-MM-DD HH:mm:ss', TIMEZONE).hour() === moment.tz(datas[i + 1].TIMESTAMP,'YYYY-MM-DD HH:mm:ss', TIMEZONE).hour()) {
    data += data.PM10
  }
  res.push(data / i)
  i = 0
 })
 return res
}

I did that for now but it's really far from the result I want

Upvotes: 1

Views: 116

Answers (1)

Nitheesh
Nitheesh

Reputation: 19996

I have generated a custom logic to generate the output as per the requirement.

You can find the details of logic and implementation in the code comment.

Working Fiddle

const data = [{
  TIMESTAMP: "2021-05-07 03:32:00.0",
  PM2_5: "27.4",
  PM10: "67.9",
  CO: "0.058",
},
{
  TIMESTAMP: "2021-05-07 03:42:00.0",
  PM2_5: "27.0",
  PM10: "67.3",
  CO: "0.026",
},
{
  TIMESTAMP: "2021-05-07 04:08:00.0",
  PM2_5: "27.0",
  PM10: "67.3",
  CO: "0.066",
}];

function getAverage(datas) {
  const output = datas.reduce((acc, curr) => {
    // Convert the date string.
    // Replace all minutes and seconds with :00
    // Replace milliseconds with .0
    const timestr = curr.TIMESTAMP
      .replaceAll(/:\d{2}/gm, ":00")
      .replaceAll(/\.\d/gm, ".0");

    // If the node with this parsed date string is avilable in accumulator, modify that node
    if (acc[timestr]) {
      // Increment the total against that particular timestamp
      ++acc[timestr].total;
      // Generate unique keys from the node in accumulator and from the current node in the data array
      const keys = [...new Set([...Object.keys(acc[timestr]), ...Object.keys(curr)])];
      // Loop through the keys and add that to node in accumulator.
      keys.forEach((key) => {
        // Donot modify key 'TIMESTAMP'
        if (key !== 'TIMESTAMP') {
          acc[timestr][key] = (+acc[timestr][key] || 0) + (+curr[key] || 0);
        }
      })
    } else {
      // If the node with this parsed date string is not available in accumulator, add that node
      acc[timestr] = { ...curr, TIMESTAMP: timestr, total: 1 };
    }
    return acc;
  }, {});
  // Generate average
  // The result of accumulator is an object
  // Convert it into Array using `Object.values(output)` and run `Array.map`
  const result = Object.values(output).map((node) => {
    // create an object rest from the value with out key total and TIMESTAMP
    const { total, TIMESTAMP, ...rest } = node;
    // Find avarage of each key
    Object.entries(rest).forEach(([key, value]) => rest[key] = +rest[key] / total);
    // Return parsed node
    return { ...rest, TIMESTAMP };
  })
  return result;
}

console.log(getAverage(data));

Upvotes: 1

Related Questions