1

I have an object in the form of:

{
"Dates": ["January", "January", "March", "March", "March", "November", "November"],
"Values": [45.6, 0.5, 59.3, 46.56, 2.21, 48.59, 5.5]
}

What I need is to aggregate the values in "Values" (average) by month

The object I am seeking:

{
"Dates":["January", "March", "November"],
"Values":[23.05, 36.02, 27]
}

I know there have been several posts about it here. But I am not sure how to apply it to an object with arrays. Would appreciate very much any ideas. Thanks

Barmar
  • 741,623
  • 53
  • 500
  • 612
Cam
  • 11
  • 2
  • 1
    Loop through the two arrays and turn it into something like `{"January": [45.6, 0.5], "March": [59.3, 46.55, 2.21], ...}`. Then it will be easy to calculate the averages of each. – Barmar Dec 09 '22 at 16:57

3 Answers3

1

Something like this should work.

// First reduce the data to an object with the dates as keys
const grouped = data.Dates.reduce((acc, date, i) => {
  if (acc[date]) {
    acc[date].push(data.Values[i])
  } else {
    acc[date] = [data.Values[i]]
  }
  return acc
}, {});

// Then reduce the object to the desired format
const result = Object.keys(grouped).reduce((acc, date) => {
  acc.Dates.push(date)
  acc.Values.push(grouped[date].reduce((a, b) => a + b) / grouped[date].length)
  return acc
}, {Dates: [], Values: []});
chribjel
  • 61
  • 3
0

You could try something like this.

const obj = {
  "Dates": ["January", "January", "March", "March", "March", "November", "November"],
  "Values": [45.6, 0.5, 59.3, 46.56, 2.21, 48.59, 5.5]
}

// new Set() will remove all duplicated items
const months = [...new Set(obj.Dates)];

const result = {
  "Dates": months,
  "Values": months.map(month => {
    // find values for given month
    const values = obj.Values.filter((_, i) => obj.Dates[i] === month);
    
    // sum the values and divide by the amount
    return values.reduce((a, b) => a + b) / values.length;
  })
}

console.log(result);
bdobry
  • 190
  • 1
  • 8
  • Bdobry, huge thanks, also to @chribjel for both of your prompt answers. Both solutions give the intended result . – Cam Dec 09 '22 at 17:25
0

You could split the tasks into smaller parts and use functions for

  • grouping,
  • getting an average of an array
  • getting the complete result by taking an object of groups.

const
    getAverage = array => array.reduce((a, b) => a + b) / array.length,
    groupBy = (keys, values) => {
        const groups = {};

        for (let i = 0; i < keys.length; i++)
            (groups[keys[i]] ??= []).push(values[i]);

        return groups;
    },
    getAverages = groups => Object.entries(groups).reduce((r, [month, values]) => {
        r.Dates.push(month);
        r.Values.push(getAverage(values));
        return r;
    }, { Dates: [], Values: [] }),
    data = { Dates: ["January", "January", "March", "March", "March", "November", "November"], Values: [45.6, 0.5, 59.3, 46.56, 2.21, 48.59, 5.5] },
    result = getAverages(groupBy(data.Dates, data.Values));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392