
本文介绍如何高效地将数据库返回的扁平化汽车数据(含 manufacture、make、model 字段)转换为符合 {manufacture: string, makes: [{make: string, models: [{model: string}]}]} 规范的嵌套 json 结构,避免多重循环与重复判断。
本文介绍如何高效地将数据库返回的扁平化汽车数据(含 manufacture、make、model 字段)转换为符合 {manufacture: string, makes: [{make: string, models: [{model: string}]}]} 规范的嵌套 json 结构,避免多重循环与重复判断。
在实际开发中,后端常以扁平化形式(如关系型数据库查询结果)返回层级数据,而前端需要将其组织为树状嵌套结构用于渲染或业务逻辑。以汽车数据为例:每条记录包含 manufacture(厂商)、make(车系)、model(型号),目标是聚合为「厂商 → 车系 → 型号」三级嵌套结构。
核心思路是利用哈希缓存(Object 或 Map)实现 O(1) 级别的层级查找与复用,避免对每个字段重复遍历数组。以下为推荐实现:
const data = [
{ manufacture: 'Ford', make: 'Mustang', model: 'EcoBoost' },
{ manufacture: 'Ford', make: 'Mustang', model: 'GTFastback' },
{ manufacture: 'Ford', make: 'Mustang', model: 'DarkHorse' },
{ manufacture: 'Ford', make: 'Escape', model: 'Active' },
{ manufacture: 'Ford', make: 'Escape', model: 'Platium' },
{ manufacture: 'Toyota', make: 'Camry', model: 'XSE' },
{ manufacture: 'Toyota', make: 'Camry', model: 'TRD' },
{ manufacture: 'Toyota', make: 'Camry', model: 'XLE' },
{ manufacture: 'Toyota', make: 'Supra', model: '2.0' },
{ manufacture: 'Toyota', make: 'Supra', model: '3.0' }
];
// 使用对象作为缓存容器,g._ 存储顶层 manufacture 对象
const g = { _: [] };
// 辅助函数:若 key 不存在则创建并推入父数组,返回该对象
const add = (arr, item) => {
arr.push(item);
return item;
};
for (const { manufacture, make, model } of data) {
// 获取或创建 manufacture 层级对象
const manuObj = g[manufacture] ??= add(g._, { manufacture, makes: [] });
// 使用 manufacturer+make 复合键避免不同厂商同名车系冲突
const makeKey = `${manufacture}:${make}`;
const makeObj = g[makeKey] ??= add(manuObj.makes, { make, models: [] });
// 直接推入 model 对象
makeObj.models.push({ model });
}
// 最终结果为 g._,即所有厂商的根数组
console.log(g._);
// 输出示例:
// [
// {
// manufacture: "Ford",
// makes: [
// {
// make: "Mustang",
// models: [{ model: "EcoBoost" }, { model: "GTFastback" }, { model: "DarkHorse" }]
// },
// {
// make: "Escape",
// models: [{ model: "Active" }, { model: "Platium" }]
// }
// ]
// },
// ...
// ]
✅ 关键设计亮点:
- 复合键防冲突:使用 manufacture:make 作为唯一键,确保不同厂商下同名车系(如 “Camry”)不会覆盖;
- 单次遍历:时间复杂度 O(n),无需嵌套 find() 或 filter();
- 可扩展性强:若需增加层级(如添加 trim 或 year),只需扩展缓存键与结构即可;
- 内存友好:仅维护必要引用,无深拷贝或冗余中间数组。
⚠️ 注意事项:
- 若原始数据中存在 manufacture 或 make 为空/undefined 值,建议前置校验,避免生成无效键(如 ":Camry");
- 生产环境可将 g 替换为 Map 实例以支持任意类型键(如 Symbol 或对象),但本例字符串键已足够;
- 如需保持插入顺序且兼容旧浏览器,可将 ??= 替换为 ||= 并配合 if (!g[key]) 判断(注意 0、"" 等 falsy 值需显式检查 in 操作符)。
该方案兼顾简洁性、性能与可维护性,是处理多级分组映射的经典模式,适用于菜单、分类、组织架构等各类树形数据构建场景。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











