How to group an array of objects by key

后端 未结 24 2965
后悔当初
后悔当初 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:44
    const reGroup = (list, key) => {
        const newGroup = {};
        list.forEach(item => {
            const newItem = Object.assign({}, item);
            delete newItem[key];
            newGroup[item[key]] = newGroup[item[key]] || [];
            newGroup[item[key]].push(newItem);
        });
        return newGroup;
    };
    
    const animals = [
      {
        type: 'dog',
        breed: 'puddle'
      },
      {
        type: 'dog',
        breed: 'labradoodle'
      },
      {
        type: 'cat',
        breed: 'siamese'
      },
      {
        type: 'dog',
        breed: 'french bulldog'
      },
      {
        type: 'cat',
        breed: 'mud'
      }
    ];
    console.log(reGroup(animals, 'type'));
    
    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(reGroup(cars, 'make'));
    
    0 讨论(0)
  • 2020-11-21 05:45

    In plain Javascript, you could use Array#reduce with an object

    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' }],
        result = cars.reduce(function (r, a) {
            r[a.make] = r[a.make] || [];
            r[a.make].push(a);
            return r;
        }, Object.create(null));
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

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

    Create a method which can be re-used

    Array.prototype.groupBy = function(prop) {
          return this.reduce(function(groups, item) {
            const val = item[prop]
            groups[val] = groups[val] || []
            groups[val].push(item)
            return groups
          }, {})
        };
    

    Then below you can group by any criteria

    const groupByMake = cars.groupBy('make');
            console.log(groupByMake);
    

    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'
        },
    ];
      //re-usable method
    Array.prototype.groupBy = function(prop) {
    	  return this.reduce(function(groups, item) {
    		const val = item[prop]
    		groups[val] = groups[val] || []
    		groups[val].push(item)
    		return groups
    	  }, {})
    	};
      
     // initiate your groupBy. Notice the recordset Cars and the field Make....
      const groupByMake = cars.groupBy('make');
    		console.log(groupByMake);
        
        //At this point we have objects. You can use Object.keys to return an array

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

    Timo's answer is how I would do it. Simple _.groupBy, and allow some duplications in the objects in the grouped structure.

    However the OP also asked for the duplicate make keys to be removed. If you wanted to go all the way:

    var grouped = _.mapValues(_.groupBy(cars, 'make'),
                              clist => clist.map(car => _.omit(car, 'make')));
    
    console.log(grouped);
    

    Yields:

    { audi:
       [ { model: 'r8', year: '2012' },
         { model: 'rs5', year: '2013' } ],
      ford:
       [ { model: 'mustang', year: '2012' },
         { model: 'fusion', year: '2015' } ],
      kia: [ { model: 'optima', year: '2012' } ] }
    

    If you wanted to do this using Underscore.js, note that its version of _.mapValues is called _.mapObject.

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

    You can try to modify the object inside the function called per iteration by _.groupBy func. Notice that the source array change his elements!

    var res = _.groupBy(cars,(car)=>{
        const makeValue=car.make;
        delete car.make;
        return makeValue;
    })
    console.log(res);
    console.log(cars);
    
    0 讨论(0)
  • 2020-11-21 05:53

    I love to write it with no dependency/complexity just pure simple js.

    const mp = {}
    const cars = [
      {
        model: 'Imaginary space craft SpaceX model',
        year: '2025'
      },
      {
        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'
      }
    ]
    
    cars.forEach(c => {
      if (!c.make) return // exit (maybe add them to a "no_make" category)
    
      if (!mp[c.make]) mp[c.make] = [{ model: c.model, year: c.year }]
      else mp[c.make].push({ model: c.model, year: c.year })
    })
    
    console.log(mp)

    0 讨论(0)
提交回复
热议问题