1

I want to group by that array to another array by name.

var cars = [
    {
        'name': 'audi',
        'model': 'r8',
        'year': '2012'
    }, {
        'name': 'audi',
        'model': 'rs5',
        'year': '2013'
    }, {
        'name': 'ford',
        'model': 'mustang',
        'year': '2012'
    }, {
        'name': 'ford',
        'model': 'fusion',
        'year': '2015'
    }
];

I expect that result (i omitted name inside items objects but I don't mind if you leave it there, if it would be to complicated (and slower):

var cars = [
 {
    name: 'audi',
    items: [
        {
            'model': 'r8',
            'year': '2012'
        }, {
            'model': 'rs5',
            'year': '2013'
        },
    ], 
  },
  {
    name: 'ford'
    items: [
        {
            'model': 'mustang',
            'year': '2012'
        }, {
            'model': 'fusion',
            'year': '2015'
        }
    ]
  }   
]

I was trying to achive that with reduce

let group = cars.reduce((r, a) => {
  r[a.name] = [...r[a.name] || [], a];
  return r;
 }, {});

but it's far from my expectation, because haven't object with name property, and without items array.

DiPix
  • 5,755
  • 15
  • 61
  • 108

2 Answers2

2

I guess this is what you needed:

var cars = [
    {
        'name': 'audi',
        'model': 'r8',
        'year': '2012'
    }, {
        'name': 'audi',
        'model': 'rs5',
        'year': '2013'
    }, {
        'name': 'ford',
        'model': 'mustang',
        'year': '2012'
    }, {
        'name': 'ford',
        'model': 'fusion',
        'year': '2015'
    }
];

let result = cars.reduce((a,v) => {
   let index = a.findIndex(el => el.name === v.name);
   if(index !== -1){
      a[index].items.push(v);
      return [...a];
   }
   return [{ name: v.name, items: [v]},...a];
},[])

console.log(result);
bill.gates
  • 14,145
  • 3
  • 19
  • 47
0

A more flexible, thus reusable approach, in terms of creating grouped lists from a single list of objects might look like the following one ...

function collectItemGroupedByKey(collector, item) {
  const groupedItemListName = collector.groupedItemListName || 'items';

  const { groupKey, index } = collector;
  const key = item[groupKey];
  let group;

  if (key in index) {

    group = index[key];
  } else {
    group = (index[key] = { [groupKey]: key, [groupedItemListName]: [] });

    collector.list.push(group);
  }
  item = Object.assign({}, item);

  if (collector.isOmitKeyInItem) {
    delete item[groupKey];
  }
  group[groupedItemListName].push(item);

  return collector;
}

const cars = [{
  'name': 'audi',
  'model': 'r8',
  'year': '2012'
}, {
  'name': 'audi',
  'model': 'rs5',
  'year': '2013'
}, {
  'name': 'ford',
  'model': 'mustang',
  'year': '2012'
}, {
  'name': 'ford',
  'model': 'fusion',
  'year': '2015'
}];


// - do what the OP was asking for and omit group key for/in each collected item.

const listsOfCarsGroupedByBrandName = cars.reduce(collectItemGroupedByKey, {

  isOmitKeyInItem: true,
  groupKey: 'name',
  index: {},
  list: []

}).list; 

console.log("listsOfCarsGroupedByBrandName : ", listsOfCarsGroupedByBrandName);


// - use the additional configuration option for a custom name of a grouped item list.
// - do not omit the group key for/in each collected item.

const listsOfCarsGroupedByYearOfManufacture  = cars.reduce(collectItemGroupedByKey, {

  groupedItemListName: 'itemList',
  groupKey: 'year',
  index: {},
  list: []
  
}).list; 

console.log("listsOfCarsGroupedByYearOfManufacture : ", listsOfCarsGroupedByYearOfManufacture);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37