如何高效将JavaScript深度嵌套数组转换为可下载CSV?
深度嵌套数组转CSV的高效实现方案
问题描述
我有一个深度嵌套数组,需要将其转换为可下载的CSV文件。目前我正通过遍历每个数组及子数组来构建CSV,想请教是否存在更高效的实现方式?
嵌套数组示例
[{ id: 123, name: "ABC", superDepartment: [{ id: 456, name: "PQR", keyCompetitor: ["JKL"], department: [{ id: 765, name: "XYZ", category: [{ id: 965, name: "GHJ", keyCompetitor: ["NMK"], otherCompetitor: ["SDF", "LKJ"], subcategory: [ {id: 346, name: "DRJ"}, {id: 789, name: "SRE"} ] }] }] }] }];
预期CSV输出
| SBU | Super Department | Department | Category | Subcategory | Key Competitor | Core Competitor | Other Competitor |
|---|---|---|---|---|---|---|---|
| ABC | |||||||
| PQR | JKL | ||||||
| XYZ | |||||||
| GHJ | NMK | SDF, LKJ | |||||
| DRJ | |||||||
| SRE |
当前实现代码
let csvData = []; downloadData.map(data => { if(csvData.length === 0) { csvData.push(data.name, "", "", "", csvData.keyCompetitors ? csvData.keyCompetitors[0] : "", csvData.coreCompetitors ? csvData.coreCompetitors.join(): "", csvData.otherCompetitors ? csvData.otherCompetitors.join() : "") } });
高效实现思路与代码
你的当前实现仅处理了最外层数据,无法覆盖深层嵌套结构。更高效的方式是使用递归遍历,它能自动适配任意嵌套层级,同时维护当前行的上下文信息,确保每一行的列值正确对齐。
步骤1:递归遍历生成CSV行数据
定义递归函数,遍历每个节点并生成对应CSV行,传递当前上下文(已填充的列值),遇到子数组则继续递归处理。
// 定义CSV表头 const headers = ["SBU", "Super Department", "Department", "Category", "Subcategory", "Key Competitor", "Core Competitor", "Other Competitor"]; // 递归遍历嵌套数组,生成CSV行数据 function generateRows(data, currentRow = {}) { let rows = []; if (data.name) { // 确定当前节点对应的列名 let columnKey; if (data.superDepartment) columnKey = "SBU"; else if (data.department) columnKey = "Super Department"; else if (data.category) columnKey = "Department"; else if (data.subcategory) columnKey = "Category"; else columnKey = "Subcategory"; // 复制上下文并填充当前节点数据 const newRow = {...currentRow}; newRow[columnKey] = data.name; // 处理竞品信息 if (data.keyCompetitor) newRow["Key Competitor"] = data.keyCompetitor.join(", "); if (data.otherCompetitor) newRow["Other Competitor"] = data.otherCompetitor.join(", "); rows.push(newRow); // 递归处理子数组(排除竞品数组) for (const key in data) { if (Array.isArray(data[key]) && !["keyCompetitor", "otherCompetitor"].includes(key)) { rows = rows.concat(data[key].map(item => generateRows(item, newRow)).flat()); } } } return rows; }
步骤2:将行数据转换为CSV字符串
按表头顺序拼接行数据,处理含逗号的值(用双引号包裹)避免格式错误。
// 将行数据转换为CSV字符串 function rowsToCsv(headers, rows) { const csvRows = [headers.join(",")]; for (const row of rows) { const csvRow = headers.map(header => { const value = row[header] || ""; return typeof value === "string" && value.includes(",") ? `"${value}"` : value; }); csvRows.push(csvRow.join(",")); } return csvRows.join("\n"); }
步骤3:生成可下载的CSV文件
通过Blob对象创建下载链接,触发浏览器下载。
// 下载CSV文件 function downloadCsv(csvContent, filename = "data.csv") { const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.setAttribute("download", filename); document.body.appendChild(link); link.click(); document.body.removeChild(link); }
完整调用示例
// 你的嵌套数组数据 const downloadData = [{ id: 123, name: "ABC", superDepartment: [{ id: 456, name: "PQR", keyCompetitor: ["JKL"], department: [{ id: 765, name: "XYZ", category: [{ id: 965, name: "GHJ", keyCompetitor: ["NMK"], otherCompetitor: ["SDF", "LKJ"], subcategory: [ {id: 346, name: "DRJ"}, {id: 789, name: "SRE"} ] }] }] }] }]; // 生成并下载CSV const allRows = downloadData.map(item => generateRows(item)).flat(); const csvContent = rowsToCsv(headers, allRows); downloadCsv(csvContent);
方案优势
- 适配任意嵌套层级:递归自动处理所有子节点,无需手动编写多层循环。
- 列值自动对齐:上下文传递确保子节点行继承父节点的空值或已有数据,符合预期格式。
- 格式安全高效:统一处理CSV转义,避免格式错误;批量拼接字符串比频繁操作数组更高效。
内容的提问来源于stack exchange,提问作者vjeta
相关产品推荐
相关产品推荐

