Reputation: 373
I'm struggling to come up with an efficient way of grouping array of objects by a property into another array.
I checked some solutions from related questions and answers however struggling to achieve needed data structure.
Sample data incoming data (taken from this q)
const cars = [{
'make': 'audi',
'model': 'r8',
'year': '2012'
}, {
'make': 'audi',
'model': 'rs5',
'year': '2013'
}, {
'make': 'ford',
'model': 'mustang',
'year': '2012'
}, {
'make': 'ford',
'model': 'fusion',
'year': '2015'
}, {
'make': 'kia',
'model': 'optima',
'year': '2012'
}, ];
here is what I'm trying to achieve:
const carsTransformed = [{
'audi': [{
'model': 'r8',
'year': '2012'
}, {
'model': 'rs5',
'year': '2013'
},],
},
{
'ford': [{
'model': 'mustang',
'year': '2012'
}, {
'model': 'fusion',
'year': '2015'
}],
},
{
'kia': [{
'model': 'optima',
'year': '2012'
}]
}
];
so far tried to use
const arrayGroupBy = (array, property) => {
return array.reduce((map, object) => {
(map[object[property]] = map[object[property]] || []).push(object);
return map;
}, {});
};
with some attempts to manipulate resulting object via Object.entries(obj).map()
getting some weird results :(
I'll appreciate any ideas on how to achieve this.
Edit: Trying to not use any third party libraries.
Upvotes: 2
Views: 73
Reputation: 417
let cars = [{
'make': 'audi',
'model': 'r8',
'year': '2012'
}, {
'make': 'audi',
'model': 'rs5',
'year': '2013'
}, {
'make': 'ford',
'model': 'mustang',
'year': '2012'
}, {
'make': 'ford',
'model': 'fusion',
'year': '2015'
}, {
'make': 'kia',
'model': 'optima',
'year': '2012'
}, ];
let rqObj = cars.reduce((acc,ele)=>{
let nObj = JSON.parse(JSON.stringify(ele));
delete nObj['make'];
let obj = {[ele.make]:[nObj]};
let pos = acc.findIndex(el=>Object.keys(el)[0]==ele.make);
(pos == -1) ? acc.push(obj) : acc[pos][ele.make] = [...acc[pos][ele.make],...obj[ele.make]];
return acc;
},[])
console.log(rqObj)
Upvotes: 1
Reputation: 207531
This is not really compact, but using delete you can remove the property from the object.
const groupBy = (obj, property = 'id') =>
Object.entries(obj.reduce((map, item) => {
var key = item[property]
map[key] = map[key] || []
const cleaned = Object.assign({}, item)
delete cleaned[property]
map[key].push(cleaned)
return map
}, {}))
.map(([k, a]) => ({
[k]: a
}))
const cars = [{
'make': 'audi',
'model': 'r8',
'year': '2012'
}, {
'make': 'audi',
'model': 'rs5',
'year': '2013'
}, {
'make': 'ford',
'model': 'mustang',
'year': '2012'
}, {
'make': 'ford',
'model': 'fusion',
'year': '2015'
}, {
'make': 'kia',
'model': 'optima',
'year': '2012'
}, ];
console.log(groupBy(cars, 'make'))
Upvotes: 2
Reputation: 2889
Maybe Like This:
const cars = [{
'make': 'audi',
'model': 'r8',
'year': '2012'
}, {
'make': 'audi',
'model': 'rs5',
'year': '2013'
}, {
'make': 'ford',
'model': 'mustang',
'year': '2012'
}, {
'make': 'ford',
'model': 'fusion',
'year': '2015'
}, {
'make': 'kia',
'model': 'optima',
'year': '2012'
}, ];
function carsTransformed(_cars){
var out = {};
for(var key in _cars){
var car_brand = _cars[key].make;
if(!out[car_brand]){
out[car_brand] = [];
}
delete(_cars[key].make);
out[car_brand].push(_cars[key]);
}
return out;
}
console.log(carsTransformed(cars));
Upvotes: 0
Reputation: 5434
let group = {};
cars.forEach((c) => {
if (!group[c.make]) group[c.make] = [];
group[c.make] = [...group[c.make], cars.filter(m => m.make === c.make)];
});
console.log(group);
or you can achieve this via lodash
library
_.mapValues(_.groupBy(cars, 'make'));
Upvotes: 0
Reputation: 4464
If you want Object here is the solution:
const carsTransformedObject = cars.reduce((acc, next) => {
if (acc[next.make]) {
acc[next.make].push({model: next.model, year: next.year})
} else {
acc[next.make] = [{model: next.model, year: next.year}]
}
return acc
}, {})
If you want this object to be in Array like you showed just do: const carsTransformed = [carsTransformedObject]
That's it 😉
Upvotes: 0
Reputation: 479
const carsTransformed = [...new Set(cars.map(c => c.make))].map(make => {
return {
[make]: cars.filter(cs => cs.make === make)
}
})
Upvotes: 1