
本文介绍如何使用 JavaScript 的 reduce 方法将数组按某个字段(如 city)分组,生成包含分组标识和子数据数组的结构化数组,而非普通对象,满足前端列表渲染等实际需求。
本文介绍如何使用 javascript 的 `reduce` 方法将数组按某个字段(如 city)分组,生成包含分组标识和子数据数组的结构化数组,而非普通对象,满足前端列表渲染等实际需求。
在实际开发中(例如构建城市-区域级联列表、消息按会话分组、订单按状态归类),我们常需将扁平数组转换为“分组容器 + 子项集合”的嵌套结构。关键诉求是:输出必须是数组(Array),每个元素是一个带 city 字段和 data 数组的对象,而非以 city 为 key 的 plain object(如 { London: [...], Manchester: [...] })。这直接关系到后续能否用 map() 渲染、是否支持 Array.isArray() 校验、以及与 React/Vue 等框架的列表指令兼容性。
下面提供一个健壮、可读性强且符合函数式习惯的实现方案:
const locations = [
{ city: "London", district: "Brixton", id: "Eue3uFjUHKi6wh73QZLX" },
{ city: "Manchester", district: "Bury", id: "QZiiUBgzZaJt2HcahELT" },
{ city: "London", district: "Hackney", id: "v2itdyO4IPXAMhIU8wce" }
];
const groupedLocations = locations.reduce((groups, item) => {
const { city } = item;
// 查找已存在的同 city 分组
const existingGroup = groups.find(group => group.city === city);
if (existingGroup) {
// 若已存在,追加当前 item 到其 data 数组
existingGroup.data.push(item);
} else {
// 否则新建分组对象,并推入 groups 数组
groups.push({ city, data: [item] });
}
return groups;
}, []);执行后,groupedLocations 将精确输出您期望的格式:
[
{
"city": "London",
"data": [
{ "city": "London", "district": "Brixton", "id": "Eue3uFjUHKi6wh73QZLX" },
{ "city": "London", "district": "Hackney", "id": "v2itdyO4IPXAMhIU8wce" }
]
},
{
"city": "Manchester",
"data": [
{ "city": "Manchester", "district": "Bury", "id": "QZiiUBgzZaJt2HcahELT" }
]
}
]✅ 核心原理说明:
Array.prototype.reduce() 的返回值类型完全由累加器(groups)的初始值及每次迭代的返回值决定。本例中传入空数组 [] 作为初始值,且每次 return groups 都返回数组引用,因此最终结果必为数组——这是解决“返回对象而非数组”问题的根本所在。
⚠️ 注意事项:
- find() 时间复杂度为 O(n),若数据量极大(如 >10,000 条),可改用 Map 做中间索引提升性能(先 reduce 构建 Map
,再 Array.from(map.values())); - 该方案保持原始数据顺序:首次出现的 city 对应的分组排在前面,后续同 city 元素追加至对应 data 中;
- 所有操作均为浅拷贝,如需深克隆原始对象,可在 push(item) 前使用 { ...item } 或结构化克隆(structuredClone(item))。
此方法简洁、无外部依赖、语义清晰,适用于绝大多数分组场景,是现代 JavaScript 数据处理的标准实践之一。










