【问题标题】:Create CSV with dynamic grouped headers in PHP from array在 PHP 中从数组创建具有动态分组标题的 CSV
【发布时间】:2020-09-29 15:18:17
【问题描述】:

请问有人可以协助完成以下任务吗? 如何从多维数组创建 CSV 导出,但要具有动态分组的列标题

Array ( 
    [0] => Array ( [months] => 06/2020 [hours] => 202 [skill] => 5 ) 
    [1] => Array ( [months] => 06/2020 [hours] => 563.5 [skill] => 6 ) 
    [2] => Array ( [months] => 07/2020 [hours] => 140.5 [skill] => 6 ) 
    [3] => Array ( [months] => 07/2020 [hours] => 522.5 [skill] => 5 ) 
)

所以 CSV 上的输出会是这样的

+----------------------------+------------+--------+
|                            | Skill 6    |Skill 5 |
+----------------------------+------------+--------+
| 06/2020                    | 563.5      | 202    |
+----------------------------+------------+--------+
| 07/2020                    | 140.5      | 522.5  |
+----------------------------+------------+--------+

添加了到目前为止的 CSV 输出 代码的当前 CSV 元素

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
foreach ($data_array as $subarray) {
    $tempKey = $subarray['skill'].$subarray['months'];  
    $subarray['hours'] = str_replace(',', '', $subarray['hours']); 
    if (isset($result[$tempKey])) {
        $result[$tempKey]['hours'] += $subarray['hours'];
    } else {
        $result[$tempKey] = $subarray;
    }
}

// CSV Output
outputCSV($result);

function outputCSV($result) {
    $output = fopen("php://output", "w");
    foreach ($result as $row) {
        fputcsv($output, $row);
    }
    fclose($output);
}

任何帮助将不胜感激,TIA

问题已编辑

【问题讨论】:

  • 这是我应得的!哈哈 下一个问题:你介意和我分享你在这个主题上的知识吗
  • 不,我不介意分享

标签: php arrays csv multidimensional-array


【解决方案1】:

很确定如果我考虑一下这个问题,我可以改进它,但它似乎得到了正确的答案

$in = [
    [ '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 ]
];

$firstTitle = 'Month';
$months = [];
$skills = [$firstTitle=>1];

// make an array keyed on the date
foreach ( $in as $t) {
    $months[$t['months']]['skill'.$t['skill']] = $t['hours'];
    $skills['skill'.$t['skill']] = 1;
}

// sort skills into assending order
ksort($skills);

// open a file
$xl = fopen('excelfile.csv', 'w');

// echo title line from the skills array
fputcsv($xl, array_keys($skills));

// build csv line with skills in the correct order
foreach ($months as $date => $m){
    // build array in correct sorted order
    $t = [];
    $t[] = $date;
    foreach ($skills as $skill => $x) {
        if ( $skill != $firstTitle) $t[] = $m[$skill];
    }
    
    fputcsv($xl,$t);  
}

结果

Month,skill5,skill6
06/2020,202,563.5
07/2020,522.5,140.5

【讨论】:

    【解决方案2】:

    您基本上只是按月汇总技能值,然后输出这些汇总值。这并不难,但你必须清楚你在做什么。我看到新玩家感到困惑的一个常见原因是他们试图使用尽可能紧凑的代码,这使得很难跟踪正在发生的事情。冗长,清楚地命名事物,并无情地评论您的代码。您将更容易了解为什么某些事情无法正常工作,并且您的代码将更易于维护。编写您的代码,就像其他人将要维护它一样。五年后别人可能就是你了。

    <?php
    $dataArray = [
        ['months' => '06/2020', 'hours' => '202', 'skill' => '5'],
        ['months' => '06/2020', 'hours' => '563.5', 'skill' => '6'],
        ['months' => '06/2020', 'hours' => '303.7', 'skill' => '6'],
        ['months' => '08/2020', 'hours' => '123.5', 'skill' => '8'],
        ['months' => '07/2020', 'hours' => '140.5', 'skill' => '6'],
        ['months' => '07/2020', 'hours' => '522.5', 'skill' => '5'],
        ['months' => '08/2020', 'hours' => '123.5', 'skill' => '6']
    ];
    
    /*
     * Break out your formatting into functions so that it's re-usable and doesn't clutter up your logic
     */
    function formatHours($hourString)
    {
        $hourString = str_replace(',', '', $hourString);
        return floatval($hourString);
    }
    
    function buildSkillKey($skillValue)
    {
        return 'Skill '.$skillValue;
    }
    
    // Set up buffers for our skills and month values
    $skills = [];
    $buffer = [];
    foreach($dataArray as $currRow)
    {
        //Format the hour value
        $currHours = formatHours($currRow['hours']);
    
        //Create key for the skill.
        $skillKey = buildSkillKey($currRow['skill']);
    
        /*
         * Add the skill to the skill buffer. Using the value as the key is an easy way to both prevent duplicates
         * without having to implement any logic, and have automatic alpha sorting
         */
        $skills[$skillKey] = $skillKey;
    
        // Set up an array for the month value if we don't have one already
        if(!array_key_exists($currRow['months'], $buffer))
        {
            $buffer[$currRow['months']] = [];
        }
    
        /*
         * If you don't have multiple month/skill entries that you need to aggregate, remove this condition
         * and simply set the value in the buffer rather than adding with +=
         */
        if(!array_key_exists($skillKey, $buffer[$currRow['months']]))
        {
            $buffer[$currRow['months']][$skillKey] = 0;
        }
    
        $buffer[$currRow['months']][$skillKey] += $currHours;
    }
    
    // Define a string for the months column header
    $monthColumnTitle = '';
    
    // Create the header row by combining the month header and the skills buffer
    $header = array_merge([$monthColumnTitle], $skills);
    
    // Open an output handle and send the header
    $outputHandle = fopen("skills.csv", "w");
    fputcsv($outputHandle, $header);
    
    // Spin through the buffer
    foreach($buffer  as $currMonth=>$currSkillValues)
    {
        // Initialize an output array with the month in the first position
        $currOutput = [$currMonth];
    
        // Iterate through the skill buffer
        foreach($skills as $currSkillLabel)
        {
            /*
             * If we have a value for this skill, add it to the output row, otherwise insert an empty string.
             *
             * If you prefer to send zeros rather than empty strings, you can just set the field value to
             * $currSkillValues[$currSkillLabel], since we initialized all skills with zeroes when building
             * the value buffer.
             */
            $currFieldValue = (!empty($currSkillValues[$currSkillLabel])) ? $currSkillValues[$currSkillLabel]:'';
            $currOutput[] = $currFieldValue;
        }
    
        // Send the row
        fputcsv($outputHandle, $currOutput);
    }
    

    【讨论】:

    • 谢谢,我也试过这个解决方案,也可以! :)
    猜你喜欢
    • 2020-04-01
    • 2014-11-04
    • 2012-05-27
    • 2013-05-06
    • 2017-04-13
    • 2020-06-17
    • 2016-06-12
    • 1970-01-01
    • 2020-12-05
    相关资源
    最近更新 更多