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.

6 Answers 6

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'))

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

3 Comments

Thanks for the answer, it will still return an object though
Weird you want it hidden in an array, but it is a simple change. Adding .map(([k,a]) => ({ [k]: a })) would make it into the array
Edited it to return an Array instead of just the object
1
const carsTransformed = [...new Set(cars.map(c => c.make))].map(make => {
    return {
        [make]: cars.filter(cs => cs.make === make)
    }
})

Comments

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)

Comments

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

Comments

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'));

1 Comment

Thanks for the answer. This will still return an object while I need an array of objects.
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));

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.