You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 08:32:56