
本文介绍使用 Node.js 合并多个 CSV 文件的正确方法,重点解决基于共同字段(如 city)的外连接(outer join)问题,避免 O(n²) 时间复杂度,推荐采用 Map 建立哈希索引实现 O(n+m) 线性合并,并提供完整可运行示例。
本文介绍使用 Node.js 合并多个 CSV 文件的正确方法,重点解决基于共同字段(如 city)的外连接(outer join)问题,避免 O(n²) 时间复杂度,推荐采用 Map 建立哈希索引实现 O(n+m) 线性合并,并提供完整可运行示例。
在 Node.js 中合并 CSV 数据时,直接嵌套循环(forEach 套 forEach)虽直观,但时间复杂度为 O(n×m),面对数千行数据将显著拖慢性能。更优解是利用哈希查找——将其中一个文件按关联键(如 city)构建成 Map,再单次遍历另一文件完成匹配与合并。这不仅将复杂度降至 O(n + m),还能自然支持不等长、无序、部分匹配的真实业务场景(如本例中 Birmingham 有交集,Seattle 和 Juneau 仅存在于一方)。
以下为推荐实现(使用 csv-parser 库解析,fs.promises 读取):
npm install csv-parser
const fs = require('fs').promises;
const csv = require('csv-parser');
// 1. 读取并解析 population.csv → 构建 city → record 映射
async function loadPopulation() {
const results = [];
const stream = fs.createReadStream('./data/population.csv');
return new Promise((resolve, reject) => {
stream
.pipe(csv({ headers: true, skipEmptyLines: true }))
.on('data', (row) => results.push(row))
.on('end', () => resolve(new Map(results.map(r => [r.city.trim(), r]))))
.on('error', reject);
});
}
// 2. 读取 temperature.csv 并与 population Map 合并(左外连接 + 补全右表缺失)
async function mergeCSVs() {
const popMap = await loadPopulation();
const tempResults = [];
const tempStream = fs.createReadStream('./data/temperature.csv');
await new Promise((resolve, reject) => {
tempStream
.pipe(csv({ headers: true, skipEmptyLines: true }))
.on('data', (row) => {
const city = row.city.trim();
const popRow = popMap.get(city) || {};
// 合并:temp 行为主,pop 字段为可选补充
tempResults.push({
index: row.index,
city: row.city,
JAN: row.JAN,
FEB: row.FEB,
ANN: row.ANN,
State: popRow.State || '',
Population: popRow.Population || ''
});
})
.on('end', () => {
// 补充 population 中存在但 temperature 中不存在的城市(如 Seattle)
for (const [city, popRow] of popMap) {
if (!tempResults.some(r => r.city.trim() === city)) {
tempResults.push({
index: '',
city: popRow.city,
JAN: '',
FEB: '',
ANN: '',
State: popRow.State,
Population: popRow.Population
});
}
}
resolve();
})
.on('error', reject);
});
return tempResults;
}
// 使用示例
mergeCSVs()
.then(console.table) // 或写入新 CSV
.catch(console.error);✅ 关键优势说明:
- Map 查找为 O(1):避免双重循环,大幅提升大数据量下的响应速度;
-
健壮的外连接逻辑:既保留
temperature.csv的全部行,也补全population.csv中未出现在温度表中的城市; -
空值处理明确:缺失字段统一置为空字符串(
''),符合示例输出格式要求; -
字段清洗:使用
.trim()消除 CSV 解析中常见的首尾空格导致匹配失败的问题。
⚠️ 注意事项:
- 若 CSV 文件含 BOM 头或特殊编码(如 GBK),需用
iconv-lite转换; - 生产环境建议添加字段校验(如
city是否为空)、类型转换(Population转Number); - 如需导出结果为 CSV,可配合
json2csv库生成标准格式文件。
该方案兼顾简洁性、性能与工程鲁棒性,是 Node.js 处理多源 CSV 关联合并的推荐实践。


















