Reputation: 173
I have an array of distinct objects. Some have the same date
value. I'd like to group those with the same date
together and return a mapped object where each date
is the key and its value is an array of the object(s) with that same date. Here's the array:
const arr = [
{
date: '2/2/20',
name: 'joe',
age: 22
},
{
date: '3/3/20',
name: 'john',
age: 67
},
{
date: '2/2/20',
name: 'chuck',
age: 34
},
{
date: '3/3/20',
name: 'bob',
age: 28
},
{
date: '4/4/20',
name: 'bill',
age: 51
}
]
I know something like this can be done with map().filter()
, but it's not what I'm looking for, and plus I'm trying to do this with reduce()
to save on resources.
So far I have:
arr.reduce((acc, person) => {
acc[person.date] = [ person ];
return acc;
}, {});
This only returns the last match, not all the matches:
{
'2/2/20': [ { date: '2/2/20', name: 'chuck', age: 34 } ],
'3/3/20': [ { date: '3/3/20', name: 'bob', age: 28 } ],
'4/4/20': [ { date: '4/4/20', name: 'bill', age: 51 } ]
}
I've tried other aspects of this solution but I can't seem to get it right. I also know how to get the mapped object that returns the count of the number of matches, but it's still not my solution:
arr.reduce((acc, person) => {
acc[person.date] = acc[person.date] + 1 || 1
return acc
}, {})
This returns:
{ '2/2/20': 2, '3/3/20': 2, '4/4/20': 1 }
So how can I use reduce()
to get an object that contains all the matches?
Upvotes: 0
Views: 62
Reputation: 4336
Jack Bashford's answer appears to be what you are looking for. I would just add that this is a very common operation often referred to as groupBy
. This is implemented in most functional helper libraries (Lodash for example). You can also implement it yourself with something like:
const groupBy = (cb, arr) =>
arr.reduce((grouped, el) => {
const key = cb(el)
return {
...grouped,
[key]: [...grouped[key] || [], el]
}
}, {})
(Note the above implementation is just an example and should not be considered a performant implementation. See Lodash groupBy implementation.
and then for your use case:
groupBy(el => el.date, arr)
which is helpful if you plan on doing similar operations.
Upvotes: 1
Reputation: 44107
Initialize to an empty array if acc[person.date]
doesn't exist, and push
regardless:
arr.reduce((acc, person) => {
acc[person.date] = (acc[person.date] || []);
acc[person.date].push(person);
return acc;
}, {});
Destructuring one-line/spreading approach:
arr.reduce((acc, { date, ...o }) => ({ ...acc, [date]: [...(acc[date] || []), { date, ...o }), {});
Upvotes: 2