php - Associative array to CSV where columns are dynamic
问题描述
Given an array such as this:
[
[
'first_name' => 'Bill',
'last_name' => 'Johnson',
'telephone' => '123-456-7890'
],
[
'first_name' => 'Kurtis',
'last_name' => 'Wild',
'telephone' => '321-654-0987'
],
[
'first_name' => 'Jane',
'last_name' => 'Doe',
'email' => 'janedoe@gmail.com'
]
]
I need to be able to write a CSV like so:
+------------+-----------+--------------+-------------------+
| first_name | last_name | telephone | email |
+------------+-----------+--------------+-------------------+
| Bill | Johnson | 123-456-7890 | |
| Kurtis | Wild | 321-654-0987 | |
| Jane | Doe | | janedoe@gmail.com |
+------------+-----------+--------------+-------------------+
The difficult part is that the telephone
and email
columns are dynamic. They exist for some rows but not others, and there can be any number of these fields that exist only on a subset of rows. All of the rows that do share a certain field need to have that field in the same column positioning. The rows that do not have this field should just have empty cells.
I guess what I'm looking for is a generic way to take an associative array as shown above and dump out a string representing a CSV that uses the array keys as headers, keeping in mind they will not match across rows.
I have already tried passing such an array into fgetcsv()
, and also tried the league/csv
package, but neither of these support this. Does anybody know a library that can do this, or perhaps even just a function that can take this type of array and spit out a correct CSV?
解决方案
foreach
如果你想保持动态,一堆循环将起作用:
# Create a key storage array
$cols = [];
foreach($arr as $row) {
foreach($row as $k => $v) {
if(!in_array($k, $cols))
$cols[$k] = '';
}
}
# Loop the main array again and merge the storage array
foreach($arr as $k => $row) {
$arr[$k] = array_merge($cols, $row);
}
给你:
Array
(
[0] => Array
(
[first_name] => Bill
[last_name] => Johnson
[telephone] => 123-456-7890
[email] =>
)
[1] => Array
(
[first_name] => Kurtis
[last_name] => Wild
[telephone] => 321-654-0987
[email] =>
)
[2] => Array
(
[first_name] => Jane
[last_name] => Doe
[telephone] =>
[email] => janedoe@gmail.com
)
)
如果您只想手动创建参考数组,您可以轻松地将空白数组与填充数组合并并获得混合数组:
$cols = [
'first_name' => '',
'last_name' => '',
'email' => '',
'telephone' => ''
];
foreach($arr as $k => $row) {
$arr[$k] = array_merge($cols, $row);
}
给你:
Array
(
[0] => Array
(
[first_name] => Bill
[last_name] => Johnson
[email] =>
[telephone] => 123-456-7890
)
[1] => Array
(
[first_name] => Kurtis
[last_name] => Wild
[email] =>
[telephone] => 321-654-0987
)
[2] => Array
(
[first_name] => Jane
[last_name] => Doe
[email] => janedoe@gmail.com
[telephone] =>
)
)
编辑:
我不确定您是否需要 CSV 函数的数组,但这只是一个快速的:
function downloadCSV($rows)
{
ob_start();
$fp = fopen('php://output', 'w');
foreach ($rows as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
$str = ob_get_contents();
ob_end_clean();
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.date('YmdHis').'file.csv"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: '.strlen($str));
echo $str;
exit;
}
因此,从上述方法之一获得数组后,只需在任何其他浏览器输出之前运行此函数:
# $arr being your array of course
downloadCSV($arr);
推荐阅读
- laravel - 必填字段的前端验证,以单选按钮的值为条件
- c# - String.Format 派生自字符串“{0}(长度要求 20)”
- angular - 如何在Angular 9中使用FormArray加载时自动检查第一个复选框
- amazon-web-services - 如何使用 CodeDeploy 最好地将代码更改部署到 ECS?
- vulkan - Vulkan 忽略 GLSL 图像格式限定符
- java - 如果被groovy分割,grep会添加新行吗?
- php - php在接收数据时崩溃,如何解决这个问题?
- regex - Sublime & Regex:如何查找所有不超过 3 个字母的行,不包括某些行?
- fortran - 在没有临时数组的情况下评估 Fortran 的 SUM(..)?
- java - Spark Java:如何通过键对 ArrayType(MapType) 进行排序并访问已排序数组的值