Home > front end >  How do I use reduce to create array of objects with repeating keys
How do I use reduce to create array of objects with repeating keys

Time:10-12

I have an array of objects that looks like this:

const data = [
  {
    "date": "2020-01-02",
    "run": [
      {"time": "1", "result": 100},
      {"time": "2", "result": 150},
      {"time": "3", "result": 92}
    ]
  },
  {
    "date": "2020-01-15",
    "run": [
      {"time": "1", "result": 90},
      {"time": "2", "result": 86},
      {"time": "3", "result": 133}
    ]
  },
  {
    "date": "2020-02-11",
    "run": [
      {"time": "1", "result": 45},
      {"time": "2", "result": 176},
      {"time": "3", "result": 108}
    ]
  },
]

I'd like it to look like this:

[
  {
    "time": 1,
    "2020-01-02": 100,
    "2020-01-15": 90,
    "2020-02-11": 45
  },
  {
    "time": 2,
    "2020-01-02": 150,
    "2020-01-15": 86,
    "2020-02-11": 176
  },
  {
    "time": 3,
    "2020-01-02": 92,
    "2020-01-15": 133,
    "2020-02-11": 108
  },
]

I've tried using reduce like this:


const initVal = {
  [data[0].date]: data[0].run[0].result
};
const newArr = data.reduce((prev, curr, currIdx) => {
  return {
    ...prev, ...initVal, [curr.date]: curr.run[currIdx-1].result
  }
});

but getting this:

{
  "2020-01-02": 100,
  "2020-01-15": 90,
  "2020-02-11": 176,
  date: "2020-01-02"
  run:[{…}, {…}, {…}]
}

So not quite there yet. I know I need it to iterate over each of the "run" arrays to get all the correct values for each "time" -- how do I set up what's missing?

CodePudding user response:

You can preprocess your array to make it easier for reduce, for example, convert it to the list of pairs [key, payload]:

data
    .flatMap(d =>
        d.run.map(r => [r.time, {[d.date]: r.result}]))

This produces:

[
  [ '1', { '2020-01-02': 100 } ],
  [ '2', { '2020-01-02': 150 } ],
  [ '3', { '2020-01-02': 92 } ],
  [ '1', { '2020-01-15': 90 } ], etc

Now we can group things together:

.reduce((m, [key, payload]) =>
    m.set(key, Object.assign({}, m.get(key), payload)),
    new Map)

which creates the following Map:

Map(3) {
  '1' => { '2020-01-02': 100, '2020-01-15': 90, '2020-02-11': 45 },
  '2' => { '2020-01-02': 150, '2020-01-15': 86, '2020-02-11': 176 },
  '3' => { '2020-01-02': 92, '2020-01-15': 133, '2020-02-11': 108 }
}

The rest should be easy, good luck!

CodePudding user response:

You could use an object for grouping and get the values as result.

const
    data = [{ date: "2020-01-02", run: [{ time: "1", result: 100 }, { time: "2", result: 150 }, { time: "3", result: 92 }] }, { date: "2020-01-15", run: [{ time: "1", result: 90 }, { time: "2", result: 86 }, { time: "3", result: 133 }] }, { date: "2020-02-11", run: [{ time: "1", result: 45 }, { time: "2", result: 176 }, { time: "3", result: 108 }] }],
    result = Object.values(data.reduce((r, { date, run }) => {
        run.forEach(({ time, result }) => {
            r[time] ??= { time };
            r[time][date] = result;
        });
        return r;
    }, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related