如何按键对对象数组进行分组

IT技术 javascript arrays object grouping lodash
2021-01-06 16:21:26

有没有人知道(如果可能的话,lodash)通过对象键对对象数组进行分组,然后根据分组创建新的对象数组的方法?例如,我有一个汽车对象数组:

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

var cars = {
    'audi': [
        {
            'model': 'r8',
            'year': '2012'
        }, {
            'model': 'rs5',
            'year': '2013'
        },
    ],

    'ford': [
        {
            'model': 'mustang',
            'year': '2012'
        }, {
            'model': 'fusion',
            'year': '2015'
        }
    ],

    'kia': [
        {
            'model': 'optima',
            'year': '2012'
        }
    ]
}
6个回答

在纯 Javascript 中,您可以Array#reduce与对象一起使用

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; }

我如何迭代result结果?
2021-02-07 16:21:26
2021-02-09 16:21:26
您可以Object.entries通过键/值对获取条目并循环。
2021-02-16 16:21:26
一如既往的最佳答案。你为什么要传递 Object.create(null)?
2021-03-03 16:21:26
有没有办法在make分组后从数据集中删除它需要额外的空间。
2021-03-08 16:21:26

Timo 的回答是我会怎么做。简单_.groupBy,并允许在分组结构中的对象中有一些重复。

但是,OP 还要求删除重复的make密钥。如果你想一路走下去:

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

console.log(grouped);

产量:

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

如果您想使用 Underscore.js 执行此操作,请注意其版本_.mapValues称为_.mapObject

您正在寻找_.groupBy().

如果需要,从对象中删除分组所依据的属性应该是微不足道的:

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>


作为奖励,您可以使用 ES6 箭头函数获得更好的语法:

const grouped = _.groupBy(cars, car => car.make);
“_”代表什么?
2021-02-11 16:21:26
@AdrianGrzywaczewski 这是名称间距“lodash”或“下划线”的默认约定。现在图书馆是module化的,它不再需要,即。npmjs.com/package/lodash.groupby
2021-02-15 16:21:26
我怎样才能对结果进行交互?
2021-02-15 16:21:26
我相信这将与 Object.keys(grouped)
2021-02-28 16:21:26
如果您还希望它更短,则根本var grouped = _.groupBy(cars, 'make');不需要函数,如果访问器是一个简单的属性名称。
2021-03-02 16:21:26

完全没有理由下载 3rd 方库来实现这个简单的问题,就像上面的解决方案所建议的那样。

在 es6 中list按某个对象对一对象进行分组的单行版本key

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

过滤掉不带 的对象的较长版本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'))

注意:似乎原始问题询问如何按制造商对汽车进行分组,但省略了每组中的制造商。因此,没有 3rd 方库的简短答案将如下所示:

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

它只是有效!任何人都可以详细说明这个减少功能吗?
2021-02-15 16:21:26
这绝对不是es5
2021-02-18 16:21:26
我喜欢你的两个答案,但我看到它们都提供“make”字段作为每个“make”数组的成员。我已经根据您的答案提供了一个答案,其中交付的输出与预期的输出相匹配。谢谢!
2021-02-28 16:21:26

这是您自己的groupBy功能,它是来自以下代码的概括:https : //github.com/you-dont-need/You-Dont-Need-Lodash-Underscore

function groupBy(xs, f) {
  return xs.reduce((r, v, i, a, k = f(v)) => ((r[k] || (r[k] = [])).push(v), r), {});
}

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 result = groupBy(cars, (c) => c.make);
console.log(result);

我喜欢这个答案,因为您也可以使用嵌套属性 - 非常好。我只是为 Typescript 更改了它,这正是我要找的 :)
2021-02-15 16:21:26