#php #arrays #csv #multidimensional-array
#php #массивы #csv #многомерный-массив
Вопрос:
Не мог бы кто-нибудь помочь в выполнении следующих задач, пожалуйста? Как создать экспорт 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
Отредактированный вопрос
Комментарии:
1. Я это заслужил! ха-ха Следующий вопрос: Не могли бы вы поделиться со мной своими знаниями по этому вопросу
2. Нет, я не против поделиться
Ответ №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);
}
Комментарии:
1. Спасибо, я также попробовал это решение, которое также работает! 🙂