PHP实现从多维数组生成带动态分组表头的CSV导出
解决方案:多维数组生成带动态分组表头的CSV
我来帮你搞定这个CSV导出的问题——要实现你想要的动态分组表头格式,核心是先把原始的扁平化数组重构为更适合二维表格的结构,然后按目标格式生成表头和内容行。下面是具体的步骤和代码调整:
1. 重构数据结构
首先,我们需要把原始数组转换成以月份为键,每个月份下存储对应各skill小时数的结构,同时收集所有唯一的skill作为动态表头的列。这一步能让我们后续更方便地按行(月份)和列(skill)组织数据:
$monthlyData = []; $skills = []; foreach ($data_array as $subarray) { $month = $subarray['months']; $skill = 'Skill ' . $subarray['skill']; // 提前格式化表头文本 $hours = (float)str_replace(',', '', $subarray['hours']); // 转为数值,方便后续累加 // 收集所有唯一的skill,用于生成表头 if (!in_array($skill, $skills)) { $skills[] = $skill; } // 合并相同月份+skill的小时数(如果有重复记录) if (isset($monthlyData[$month][$skill])) { $monthlyData[$month][$skill] += $hours; } else { $monthlyData[$month][$skill] = $hours; } } // 调整skill的顺序(对应你例子中Skill 6在前、Skill 5在后的需求) sort($skills); $skills = array_reverse($skills);
2. 修改CSV输出逻辑
接下来,我们需要重写outputCSV函数,先输出动态生成的表头,再按月份遍历输出每行数据:
function outputCSV($monthlyData, $skills) { $output = fopen("php://output", "w"); // 生成表头行:第一列为空(对应月份列的表头),后面是各个skill $header = ['']; $header = array_merge($header, $skills); fputcsv($output, $header); // 遍历每个月份,生成内容行 foreach ($monthlyData as $month => $skillHours) { $row = [$month]; // 按表头的skill顺序填充小时数,没有对应记录则填0(可改为空字符串'') foreach ($skills as $skill) { $row[] = isset($skillHours[$skill]) ? $skillHours[$skill] : 0; } fputcsv($output, $row); } fclose($output); }
3. 完整整合代码
把所有部分整合起来,替换你原来的代码片段即可:
header("Content-type: text/csv"); header("Content-Disposition: attachment; filename=result_file.csv"); header("Pragma: no-cache"); header("Expires: 0"); // Building $data_array from DB(这里保留你从数据库获取数据的逻辑) $data_array = [ ['months' => '06/2020', 'hours' => '202', 'skill' => 5], ['months' => '06/2020', 'hours' => '563.5', 'skill' => 6], ['months' => '07/2020', 'hours' => '140.5', 'skill' => 6], ['months' => '07/2020', 'hours' => '522.5', 'skill' => 5], ]; // 数据重构 $monthlyData = []; $skills = []; foreach ($data_array as $subarray) { $month = $subarray['months']; $skill = 'Skill ' . $subarray['skill']; $hours = (float)str_replace(',', '', $subarray['hours']); if (!in_array($skill, $skills)) { $skills[] = $skill; } if (isset($monthlyData[$month][$skill])) { $monthlyData[$month][$skill] += $hours; } else { $monthlyData[$month][$skill] = $hours; } } // 调整表头顺序 sort($skills); $skills = array_reverse($skills); // CSV输出函数 function outputCSV($monthlyData, $skills) { $output = fopen("php://output", "w"); $header = ['']; $header = array_merge($header, $skills); fputcsv($output, $header); foreach ($monthlyData as $month => $skillHours) { $row = [$month]; foreach ($skills as $skill) { $row[] = isset($skillHours[$skill]) ? $skillHours[$skill] : 0; } fputcsv($output, $row); } fclose($output); } // 调用输出 outputCSV($monthlyData, $skills);
关键细节说明
- 动态表头:通过收集所有唯一的skill,不管后续新增多少种skill,表头都会自动适配。
- 数据合并:保留了你原来的重复记录累加逻辑,确保同一个月份+skill的小时数会被合并。
- 空值处理:如果某个月份没有某个skill的记录,默认填充
0,你可以根据需求改成空字符串''。 - 顺序调整:通过
sort和array_reverse实现了Skill 6在前的顺序,你可以根据需要修改排序逻辑(比如按skill编号升序则去掉array_reverse)。
导出后的CSV用Excel或文本编辑器打开,会完全匹配你期望的格式。
内容的提问来源于stack exchange,提问作者Ade Mitchell
相关产品推荐
相关产品推荐

