How to group an array of objects by key

后端 未结 24 2788
后悔当初
后悔当初 2020-11-21 05:13

Does anyone know of a (lodash if possible too) way to group an array of objects by an object key then create a new array of objects based on the grouping? For example, I hav

相关标签:
24条回答
  • 2020-11-21 05:54

    There is absolutely no reason to download a 3rd party library to achieve this simple problem, like the above solutions suggest.

    The one line version to group a list of objects by a certain key in es6:

    const groupByKey = (list, key) => list.reduce((hash, obj) => ({...hash, [obj[key]]:( hash[obj[key]] || [] ).concat(obj)}), {})
    

    The longer version that filters out the objects without the key:

    function groupByKey(array, key) {
       return array
         .reduce((hash, obj) => {
           if(obj[key] === undefined) return hash; 
           return Object.assign(hash, { [obj[key]]:( hash[obj[key]] || [] ).concat(obj)})
         }, {})
    }
    
    
    var 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(groupByKey(cars, 'make'))

    NOTE: It appear the original question asks how to group cars by make, but omit the make in each group. So the short answer, without 3rd party libraries, would look like this:

    const groupByKey = (list, key, {omitKey=false}) => list.reduce((hash, {[key]:value, ...rest}) => ({...hash, [value]:( hash[value] || [] ).concat(omitKey ? {...rest} : {[key]:value, ...rest})} ), {})
    
    var 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(groupByKey(cars, 'make', {omitKey:true}))

    0 讨论(0)
  • 2020-11-21 05:55

    You are looking for _.groupBy().

    Removing the property you are grouping by from the objects should be trivial if required:

    var 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'},];
    
    var grouped = _.groupBy(cars, function(car) {
      return car.make;
    });
    
    console.log(grouped);
    <script src='https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js'></script>


    As a bonus, you get even nicer syntax with ES6 arrow functions:

    const grouped = _.groupBy(cars, car => car.make);
    
    0 讨论(0)
  • 2020-11-21 05:55

    For cases where key can be null and we want to group them as others

    var 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'},
                {'make':'kia','model':'optima','year':'2033'},
                {'make':null,'model':'zen','year':'2012'},
                {'make':null,'model':'blue','year':'2017'},
    
               ];
    
    
     result = cars.reduce(function (r, a) {
            key = a.make || 'others';
            r[key] = r[key] || [];
            r[key].push(a);
            return r;
        }, Object.create(null));
    
    0 讨论(0)
  • 2020-11-21 05:55

    You can also make use of array#forEach() method 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' }];
    
    let newcars = {}
    
    cars.forEach(car => {
      newcars[car.make] ? // check if that array exists or not in newcars object
        newcars[car.make].push({model: car.model, year: car.year})  // just push
       : (newcars[car.make] = [], newcars[car.make].push({model: car.model, year: car.year})) // create a new array and push
    })
    
    console.log(newcars);

    0 讨论(0)
  • 2020-11-21 05:55

    With lodash/fp you can create a function with _.flow() that 1st groups by a key, and then map each group, and omits a key from each item:

    const { flow, groupBy, mapValues, map, omit } = _;
    
    const groupAndOmitBy = key => flow(
      groupBy(key),
      mapValues(map(omit(key)))
    );
    
    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' }];
    
    const groupAndOmitMake = groupAndOmitBy('make');
    
    const result = groupAndOmitMake(cars);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    <script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

    0 讨论(0)
  • 2020-11-21 05:57

    Its also possible with a simple for loop:

     const result = {};
    
     for(const {make, model, year} of cars) {
       if(!result[make]) result[make] = [];
       result[make].push({ model, year });
     }
    
    0 讨论(0)
提交回复
热议问题