2

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.

Sharif
  • 343
  • 3
  • 12

6 Answers6

2

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'))
epascarello
  • 204,599
  • 20
  • 195
  • 236
1
const carsTransformed = [...new Set(cars.map(c => c.make))].map(make => {
    return {
        [make]: cars.filter(cs => cs.make === make)
    }
})
Al Hill
  • 479
  • 2
  • 6
1

 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)
Guvaliour
  • 397
  • 1
  • 5
  • 17
0
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'));

hendrixchord
  • 4,662
  • 4
  • 25
  • 39
0

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

You can try it here

Adam Orłowski
  • 4,268
  • 24
  • 33
0

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));
mscdeveloper
  • 2,749
  • 1
  • 10
  • 17