Search code examples
javascriptarraysecmascript-6reduce

Transform nested object of objects of arrays in JS


Besides the horrible name of the question my question is quite simple. I have this object:

let test = {
  date1: [
    {
      time: 1,
      value: 5,
    },
    {
      time: 2,
      value: 6,
    },
  ],
  date2: [
    {
      time: 1,
      value: 20,
    },
    {
      time: 2,
      value: 10,
    },
  ],
};

That I want to transform to something like this:

let result = {
  date1: {
    values: [5, 6],
    times: [1, 2],
  },
  date2: {
    values: [1, 2], // easier to summarise?!
    times: [10, 20],
  },
};

I actually want to do this in order to summarise the value-values for each date. I thought that if I have them in an array it would be easier to summarise them. I know there are other forms to do this (and I'd be happy to see any solutions).

My current approach does not what I want it to do. It looks like this:

let keys = Object.keys(test);
let red = keys.reduce((acc, curr) => {
  return (acc[curr] = test[curr].map((e) => e.value));
}, {});

console.log(`red: `, red);

And produces this:

red: [ 20, 10 ]


Solution

  • This

    return (acc[curr] = test[curr].map((e) => e.value));
    

    is equivalent to

    acc[curr] = test[curr].map((e) => e.value);
    return acc[curr];
    

    going inside a nested key of the accumulator on every iteration - which isn't the logic you want. Return the whole accumulator on a separate line, so previously assigned values don't get lost, and you also need to account for both the time and value properties of the array being iterated over - your => e.value only extracts one of the two properties you want.

    let test = {
      date1: [
        {
          time: 1,
          value: 5,
        },
        {
          time: 2,
          value: 6,
        },
      ],
      date2: [
        {
          time: 1,
          value: 20,
        },
        {
          time: 2,
          value: 10,
        },
      ],
    };
    
    const keys = Object.keys(test);
    const result = keys.reduce((acc, key) => {
      acc[key] = {
        values: test[key].map(({ value }) => value),
        times: test[key].map(({ time }) => time),
      };
      return acc;
      return acc;
    }, {});
    
    console.log(result);

    or do

    let test = {
      date1: [
        {
          time: 1,
          value: 5,
        },
        {
          time: 2,
          value: 6,
        },
      ],
      date2: [
        {
          time: 1,
          value: 20,
        },
        {
          time: 2,
          value: 10,
        },
      ],
    };
    
    const result = Object.fromEntries(
      Object.entries(test).map(([key, arr]) => [
        key,
        {
          values: arr.map(({ value }) => value),
          times: arr.map(({ time }) => time),
        }
      ])
    );
    console.log(result);