1
arr = [ 

    {
       day: "monday",
       ages: [1,5,2]
    },

    {
       day: "tuesday",
       ages: [9]
    },

    {
       day: "monday",
       ages: [22,24,28]
    },

    {
       day: "tuesday",
       ages: [19]
    },

]

I want the result to be an object that has each day as a key and the values as arrays:

expected:

{
    monday: [1,5,2,22,24,28],
    tuesday: [9,19]
}

I tried using reduce as follows:

x = arr.reduce((acc,curr) => {
    acc[curr.day] = []
    acc[curr.day].push(curr.ages)
    return acc
})

but it gives me:

{
    ages: [1,5,2],
    day: "tuesday", 
    monday: [22,24,28],
    tuesday: [19]
}

why would it add ages and day as keys?

0

3 Answers 3

2

Missing initial value in reduce {}, then array is not reused in each iteration , and finally arrays are not concatenated.

arr = [ 

    {
       day: "monday",
       ages: [1,5,2]
    },

    {
       day: "tuesday",
       ages: [9]
    },

    {
       day: "monday",
       ages: [22,24,28]
    },

    {
       day: "tuesday",
       ages: [19]
    },

]

console.log(arr.reduce((acc,curr) => {
    acc[curr.day] = acc[curr.day] || []
    acc[curr.day] = acc[curr.day].concat(curr.ages)
    return acc
}, {}));

Sign up to request clarification or add additional context in comments.

Comments

2

You could take a logical nullish assignment ??= for assigning empty array and push spreaded array and take an empty object as start value for the accumulator.

x = arr.reduce((acc,curr) => {
    acc[curr.day] ??= [];
    acc[curr.day].push(...curr.ages);
    return acc;
}, {});

3 Comments

This code would also work with the good old || operator that has greater support (arrays can't be falsy).
@FZs, ??= prevents superfluous assignment, like the new ||=.
That's right, I've just mentioned it as ??= is a very new feature, and not everyone transpile their projects. Btw, I'd use (acc[curr.day] || (acc[curr.day] = [])).push(...curr.ages); that short-circuits as well.
1

It helps when you specify the initial value for the reducer (ie: {}) so you can simply check to see if the property is there and if so, add to it, and if not, set it.

const arr = [ 
    {
       day: "monday",
       ages: [1,5,2]
    },

    {
       day: "tuesday",
       ages: [9]
    },

    {
       day: "monday",
       ages: [22,24,28]
    },

    {
       day: "tuesday",
       ages: [19]
    },
];

const result = arr.reduce((acc,curr) => {
    acc[curr.day] = acc[curr.day] ? [...acc[curr.day], ...curr.ages] : curr.ages; 
    return acc;
}, {});
console.log(result);

For the second argument to Array.reduce(Func, InitialValue) the general rule is that it is needed when you need to do something more complex with the accumulator before modifying it. In the below example, you can see that a simple reduce function add ints doesn't require an initial value. But the second example where we need to check to see if the acc contains the curr before adding it to the acc, you'll want to initialize acc is an empty array. otherwise, acc is undefined in the first run, and therefore acc.find will throw a null exception.

const arr = [1, 2, 3, 4];

// Simple summing of ints
console.log(arr.reduce( (acc, curr) => acc += curr) );

// Needing to do something with the accumulator before modiyfing it
const result = arr.reduce( (acc, curr) => {
  const found = acc.find(a => a === curr);
  if (found) {
    // do something
  }
  return acc;
});

From the docs:

InitialValue

A value to use as the first argument to the first call of the callback. If no initialValue is supplied, the first element in the array will be used as the initial accumulator value and skipped as currentValue. Calling reduce() on an empty array without an initialValue will throw a TypeError.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.