如何将给定数组按category属性分组生成新的对象数组?
按category分组数组的实现方案及性能分析
需求说明
给定如下汽车数组:
const CARS = [ {make: "skoda", model: "kodiaq", color: "light-blue", id: "1002", category: "A"}, {make: "skoda", model: "karoq", color: "green", id: "1008", category: "B"}, {make: "renault", model: "clio", color: "grey", id: "1006", category: "A"}, {make: "renault", model: "kangoo", color: "white", id: "1042", category: "C"}, {make: "mazda", model: "cx3", color: "red", id: "1022", category: "C"}, {make: "mazda", model: "cx30", color: "orange", id: "1106", category: "D"}, {make: "ford", model: "explorer", color: "grey", id: "1162", category: "B"}, {make: "ford", model: "edge", color: "red", id: "1862", category: "A"} ];
需要将其转换为按category分组的数组,格式如下:
const NEW_CARS = [ { category: "A", data: [ {make: "skoda", model: "kodiaq", color: "light-blue", id: "1002", category: "A"}, {make: "renault", model: "clio", color: "grey", id: "1006", category: "A"}, {make: "ford", model: "edge", color: "red", id: "1862", category: "A"} ] }, { category: "B", data: [ {make: "skoda", model: "karoq", color: "green", id: "1008", category: "B"}, {make: "ford", model: "explorer", color: "grey", id: "1162", category: "B"} ] }, { category: "C", data: [ {make: "renault", model: "kangoo", color: "white", id: "1042", category: "C"}, {make: "mazda", model: "cx3", color: "red", id: "1022", category: "C"} ] }, { category: "D", data: [ {make: "mazda", model: "cx30", color: "orange", id: "1106", category: "D"} ] } ];
同时需要考虑大数组场景下的性能最优实现。
实现方案
1. 性能最优方案:对象映射+reduce+Object.values
该方案仅遍历原数组一次,通过对象映射将category作为键,避免重复查找,时间复杂度为O(n),适合大数组场景:
// 第一步:用reduce构建类别映射对象 const groupMap = CARS.reduce((map, car) => { const category = car.category; // 若当前类别未在映射中,初始化分组对象 if (!map[category]) { map[category] = { category, data: [] }; } // 将当前车辆加入对应分组的data数组 map[category].data.push(car); return map; }, {}); // 第二步:将映射对象转为目标格式的数组 const NEW_CARS = Object.values(groupMap);
2. 简洁但性能一般的方案:去重类别+map+filter
代码简洁直观,但需多次遍历数组,时间复杂度为O(n*k)(k为类别数量),仅适合小数组或类别极少的场景:
// 提取所有唯一的category const uniqueCategories = [...new Set(CARS.map(car => car.category))]; // 遍历每个类别,过滤出对应车辆组成分组 const NEW_CARS = uniqueCategories.map(category => ({ category, data: CARS.filter(car => car.category === category) }));
3. 不推荐的方案:直接reduce+find
每次迭代需遍历累加器数组查找分组,时间复杂度为O(n²),数组越大性能下降越明显:
const NEW_CARS = CARS.reduce((acc, car) => { // 查找当前类别已存在的分组 const existingGroup = acc.find(item => item.category === car.category); if (existingGroup) { existingGroup.data.push(car); } else { acc.push({ category: car.category, data: [car] }); } return acc; }, []);
性能对比
| 方案 | 时间复杂度 | 适用场景 |
|---|---|---|
| 对象映射+reduce+Object.values | O(n) | 大数组、类别数量多的场景 |
| 去重类别+map+filter | O(n*k) | 小数组、类别数量极少的场景 |
| 直接reduce+find | O(n²) | 无优势,不推荐使用 |
内容的提问来源于stack exchange,提问作者Butri
相关产品推荐
相关产品推荐

