Javascript 数组如何按两个属性分组?

Javascript 数组如何按两个属性分组?,javascript,arrays,ecmascript-6,Javascript,Arrays,Ecmascript 6,Ex: const arr = [{ group: 1, question: { templateId: 100 } }, { group: 2, question: { templateId: 200 } }, { group: 1, question: { templateId: 100 } }, { group: 1, question: { templateId: 300 } }]; 预期结果:const

Ex:

const arr = [{
  group: 1,
  question: {
    templateId: 100
  }
}, {
  group: 2,
  question: {
    templateId: 200
  }
}, {
  group: 1,
  question: {
    templateId: 100
  }
}, {
  group: 1,
  question: {
    templateId: 300
  }
}];
预期结果:
const Result=groupBy(arr,'group','question.templateId')


到目前为止:我可以使用单个属性对结果进行分组

功能分组依据(arr,键){
返回[…arr.reduce((累加器,当前值)=>{
const propVal=当前值[键],
组=累加器.get(propVal)| |[];
分组推送(currentValue);
返回累加器.set(propVal,group);
},新映射())。值()];
}
常数arr=[{
组别:1,,
问题:{
模板ID:100
}
}, {
组别:2,,
问题:{
模板ID:200
}
}, {
组别:1,,
问题:{
模板ID:100
}
}, {
组别:1,,
问题:{
模板ID:300
}
}];
const result=groupBy(arr,'group');

控制台日志(结果)我建议传递回调函数而不是属性名,这样可以轻松地进行两级访问:

function groupBy(arr, key) {
  return Array.from(arr.reduce((accumulator, currentValue) => {
    const propVal = key(currentValue),
//                  ^^^^            ^
          group = accumulator.get(propVal) || [];
    group.push(currentValue);
    return accumulator.set(propVal, group);
  }, new Map()).values());
}
现在您可以执行
groupBy(arr,o=>o.group)
groupBy(arr,o=>o.question.templateId)

要获得预期结果,只需按第一个属性分组,然后按第二个属性分组每个结果:

function concatMap(arr, fn) {
  return [].concat(...arr.map(fn));
}
const result = concatMap(groupBy(arr, o => o.group), res =>
  groupBy(res, o => o.question.templateId)
);

@如果您可以对输入进行硬编码,那么Bergi的答案非常好

如果要使用字符串输入,可以使用
sort()
方法,并根据需要遍历对象

此解决方案将处理任意数量的参数:

功能分组依据(arr){
var arg=参数;
返回arr.sort((a,b)=>{
var i、key、aval、bval;
对于(i=1;ibval)返回1;
}
返回0;
});
}
常数arr=[{
组别:1,,
问题:{
模板ID:100
}
}, {
组别:2,,
问题:{
模板ID:200
}
}, {
组别:1,,
问题:{
模板ID:100
}
}, {
组别:1,,
问题:{
模板ID:300
}
}];
const result=groupBy(arr,'group','question.templateId');

控制台日志(结果)@Bergi的答案非常实用,但我将向您展示如何使用JavaScript原语构建多值“键”——不要认为这意味着Bergi的答案在任何方面都不好;事实上,由于它的实用性,它实际上要好得多。如果有什么问题的话,这个答案的存在是为了告诉你使用像他的方法可以节省多少工作量

我将一点一点地检查代码,然后在最后有一个完整的可运行演示


复合数据相等性

比较JavaScript中的复合数据有点棘手,因此我们需要首先找到一种解决方法:


console.log([1,2]=[1,2])//false
非常感谢Naomik为您的回答所做的努力和出色的解释。一步一步的解释非常清晰、一致和友好——它确实帮助我更好地理解了我的需求本身,以及如何用不同的方法解决它。一个
+1
是不够的,所以再次感谢
:)
。瑞奇,我很高兴能帮上忙^^哇,非常彻底
function concatMap(arr, fn) {
  return [].concat(...arr.map(fn));
}
const result = concatMap(groupBy(arr, o => o.group), res =>
  groupBy(res, o => o.question.templateId)
);