有没有人知道(如果可能的话,还是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'
}
]
}
答案 0 :(得分:155)
在普通的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; }

答案 1 :(得分:51)
Timo's answer就是这样做的。简单_.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
。
答案 2 :(得分:45)
您正在寻找_.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>
&#13;
作为奖励,您可以使用ES6箭头功能获得更好的语法:
const grouped = _.groupBy(cars, car => car.make);
答案 3 :(得分:23)
通过es6中的某个键对对象数组进行分组的简短版本:
result = array.reduce((h, obj) => Object.assign(h, { [obj.key]:( h[obj.key] || [] ).concat(obj) }), {})
版本较长:
result = array.reduce(function(h, obj) {
h[obj.key] = (h[obj.key] || []).concat(obj);
return h;
}, {})
看来原始问题询问如何通过make对汽车进行分组,但省略了每个组中的make。所以答案看起来像这样:
result = cars.reduce((h, {model,year,make}) => {
return Object.assign(h, { [make]:( h[make] || [] ).concat({model,year})})
}, {})
答案 4 :(得分:7)
您可以尝试通过_.groupBy func修改每次迭代调用的函数内的对象。 请注意,源数组会更改其元素!
var res = _.groupBy(cars,(car)=>{
const makeValue=car.make;
delete car.make;
return makeValue;
})
console.log(res);
console.log(cars);
答案 5 :(得分:3)
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'
}].reduce((r, a) => {
r[a.make] = [...r[a.make] || [], a];
return r;
}, {});
console.log(cars);
答案 6 :(得分:3)
对于key可以为null的情况,我们希望将它们分组为 others
main
答案 7 :(得分:3)
也可以通过简单的for
循环来实现:
const result = {};
for(const {make, model, year} of cars) {
if(!result[make]) result[make] = [];
result[make].push({ model, year });
}
答案 8 :(得分:2)
创建可以重复使用的方法
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
}, {})
};
然后您可以在下面按任何条件分组
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
答案 9 :(得分:2)
只需简单的 forEach 循环就可以在这里工作,无需任何库
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'
},
];
let ObjMap ={};
cars.forEach(element => {
var makeKey = element.make;
if(!ObjMap[makeKey]) {
ObjMap[makeKey] = [];
}
ObjMap[makeKey].push({
model: element.model,
year: element.year
});
});
console.log(ObjMap);
答案 10 :(得分:2)
也使用ES6的原型版本。 基本上,这使用reduce函数传入一个累加器和当前项,然后使用该函数根据传入的键构建“分组”数组。 reduce的内部看起来可能很复杂,但实际上它正在测试以查看传入对象的键是否存在,如果不存在,则创建一个空数组并将当前项附加到该新创建的数组,否则使用散点图运算符传入当前键数组的所有对象并追加当前项。希望这对某人有帮助!。
Array.prototype.groupBy = function(k) {
return this.reduce((acc, item) => ((acc[item[k]] = [...(acc[item[k]] || []), item]), acc),{});
};
const projs = [
{
project: "A",
timeTake: 2,
desc: "this is a description"
},
{
project: "B",
timeTake: 4,
desc: "this is a description"
},
{
project: "A",
timeTake: 12,
desc: "this is a description"
},
{
project: "B",
timeTake: 45,
desc: "this is a description"
}
];
console.log(projs.groupBy("project"));
答案 11 :(得分:2)
我将REAL GROUP BY
留给JS Arrays示例使用,与此任务here完全相同
const inputArray = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
var outObject = inputArray.reduce(function(a, e) {
// GROUP BY estimated key (estKey), well, may be a just plain key
// a -- Accumulator result object
// e -- sequentally checked Element, the Element that is tested just at this itaration
// new grouping name may be calculated, but must be based on real value of real field
let estKey = (e['Phase']);
(a[estKey] ? a[estKey] : (a[estKey] = null || [])).push(e);
return a;
}, {});
console.log(outObject);
Даздравствуютвысокиепоказателимастерствапрограммистоввоимяпроцветаниявсегочеловечества! Ура,товарищи!
答案 12 :(得分:1)
只需尝试一下,对我来说就很好了。
let grouped = _.groupBy(cars, 'make');
答案 13 :(得分:1)
我喜欢编写无依赖性/复杂性的纯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)
答案 14 :(得分:1)
答案 15 :(得分:0)
我喜欢@metakunfu的答案,但它没有完全提供预期的输出。 这是更新的版本,在最终的JSON有效负载中消除了“ make”。
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((h, car) => Object.assign(h, { [car.make]:( h[car.make] || [] ).concat({model: car.model, year: car.year}) }), {})
console.log(JSON.stringify(result));
输出:
{
"audi":[
{
"model":"r8",
"year":"2012"
},
{
"model":"rs5",
"year":"2013"
}
],
"ford":[
{
"model":"mustang",
"year":"2012"
},
{
"model":"fusion",
"year":"2015"
}
],
"kia":[
{
"model":"optima",
"year":"2012"
}
]
}
答案 16 :(得分:0)
您还可以像这样使用array#forEach()
方法:
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);
答案 17 :(得分:0)
使用lodash / fp,您可以使用_.flow()
创建一个函数,该函数将第一个键按组分组,然后映射每个组,并从每个项目中省略键:
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>
答案 18 :(得分:0)
如果您不想在所有字段中都键入内容,请以@Jonas_Wilms的answer为基础:
var result = {};
for ( let { first_field, ...fields } of your_data )
{
result[first_field] = result[first_field] || [];
result[first_field].push({ ...fields });
}
我没有进行任何基准测试,但我相信使用for循环也比this answer中建议的任何方法更有效。
答案 19 :(得分:0)
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'));
答案 20 :(得分:0)
这是一个受Java中Collectors.groupingBy()启发的解决方案:
function groupingBy(list, keyMapper) {
return list.reduce((accummalatorMap, currentValue) => {
const key = keyMapper(currentValue);
if(!accummalatorMap.has(key)) {
accummalatorMap.set(key, [currentValue]);
} else {
accummalatorMap.set(key, accummalatorMap.get(key).push(currentValue));
}
return accummalatorMap;
}, new Map());
}
这将提供一个Map对象。
// Usage
const carMakers = groupingBy(cars, car => car.make);
答案 21 :(得分:0)
打字稿中的对象分组数组,其内容如下:
groupBy (list: any[], key: string): Map<string, Array<any>> {
let map = new Map();
list.map(val=> {
if(!map.has(val[key])){
map.set(val[key],list.filter(data => data[key] == val[key]));
}
});
return map;
});
答案 22 :(得分:0)
同意,除非您经常使用它们,否则不需要外部库。尽管可以使用类似的解决方案,但如果您想了解正在发生的事情,我发现其中有些很难遵循here is a gist的注释解决方案。
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'
}, ];
/**
* Groups an array of objects by a key an returns an object or array grouped by provided key.
* @param array - array to group objects by key.
* @param key - key to group array objects by.
* @param removeKey - remove the key and it's value from the resulting object.
* @param outputType - type of structure the output should be contained in.
*/
const groupBy = (
inputArray,
key,
removeKey = false,
outputType = {},
) => {
return inputArray.reduce(
(previous, current) => {
// Get the current value that matches the input key and remove the key value for it.
const {
[key]: keyValue
} = current;
// remove the key if option is set
removeKey && keyValue && delete current[key];
// If there is already an array for the user provided key use it else default to an empty array.
const {
[keyValue]: reducedValue = []
} = previous;
// Create a new object and return that merges the previous with the current object
return Object.assign(previous, {
[keyValue]: reducedValue.concat(current)
});
},
// Replace the object here to an array to change output object to an array
outputType,
);
};
console.log(groupBy(cars, 'make', true))
答案 23 :(得分:-1)
function groupBy(data, property) {
return data.reduce((acc, obj) => {
const key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
groupBy(people, 'age');
答案 24 :(得分:-1)
这是另一种解决方案。根据要求。
我想制作一个新的汽车对象阵列,按make分组:
function groupBy() {
const key = 'make';
return cars.reduce((acc, x) => ({
...acc,
[x[key]]: (!acc[x[key]]) ? [{
model: x.model,
year: x.year
}] : [...acc[x[key]], {
model: x.model,
year: x.year
}]
}), {})
}
输出:
console.log('Grouped by make key:',groupBy())