(PHP) CSV 更改列顺序
(PHP) CSV Change column order
我目前正在尝试操作 CSV 文件。我希望能够更改列的顺序。
所以我最初的想法是读取哪个列应该在哪个位置,然后将这些列按顺序放入另一个数组,完成后覆盖原始数组。
遗憾的是,在遍历 csv 时,数组是基于行而不是基于列的。
在 PHP 中有没有一种方法可以像翻转 table 那样改变顺序?
没有内置函数可以执行此操作,您将不得不自己动手。如果您将整个文件读入数组然后对其执行某种转换,那么对 CSV 中的数据执行此类操作可能会导致内存问题,因此最好逐行执行此操作。这样您就可以将行流式传输到一个新文件,而不是将它们全部存储在一个大数组中。
这是一个快速而粗略的解决方案,您可以在其中提供列索引数组来定义新顺序。简单有效。
输入:
Header A,Header B,Header C,Header D
a,b,c,d
1,2,3,4
alpha,bravo,charlie,delta
$fh = fopen('reorder.csv', 'r');
/*
* Create an array with column indices in the order that they
* should appear in the output.
*
* Each column that should appear in the output must be included.
* This is both a feature and a potential gotcha.
*/
$colSpec = [0,3,2,1];
// Output buffer
$output = [];
while($currRow = fgetcsv($fh))
{
// Buffer for our output row
$currOutput = [];
/*
* Loop through the spec array and populate the row output buffer
* using the indices defined there
*/
foreach($colSpec as $currColumnIndex)
{
$currOutput[] = $currRow[$currColumnIndex];
}
// Append the new reordered row to the output buffer
$output[] = $currOutput;
}
fclose($fh);
print_r($output);
输出:
Array
(
[0] => Array
(
[0] => Header A
[1] => Header D
[2] => Header C
[3] => Header B
)
[1] => Array
(
[0] => a
[1] => d
[2] => c
[3] => b
)
[2] => Array
(
[0] => 1
[1] => 4
[2] => 3
[3] => 2
)
[3] => Array
(
[0] => alpha
[1] => delta
[2] => charlie
[3] => bravo
)
)
虽然这不是很直观,但数字索引使得很难从逻辑上理解哪个列要去哪里。如果您的 CSV 有一个 header 行,并且该行中的标签是不可变的,您可以这样做以使其更直观:
/*
* Create an array with header values in the order that they
* should appear in the output.
*
* Each column that should appear in the output must be included.
* This is both a feature and a potential gotcha.
*/
$colSpec = ['Header C', 'Header A', 'Header B', 'Header D'];
// Create a map for column name to actual index in the file
$headerIndexMap = array_flip($colSpec);
// Output buffer
$output = [];
while ($currRow = fgetcsv($fh))
{
// If this is our first row, set up the column mapping
if(empty($output))
{
// Loop through the columns...
foreach($currRow as $index => $currHeaderLabel)
{
/*
* Trim the header value, in case there it leading/trailing whitespace in the data
*/
$currHeaderLabel = trim($currHeaderLabel);
// If this column is in our column spec, set the index in $headerIndexMap
if(array_key_exists($currHeaderLabel, $headerIndexMap))
{
$headerIndexMap[$currHeaderLabel] = $index;
}
}
}
// Buffer for our output row
$currOutput = [];
// Loop through the column spec...
foreach ($colSpec as $currColumn)
{
// Get the actual index of the column from the index map
$currIndex = $headerIndexMap[$currColumn];
// Append the data in the appropriate column to the row output buffer
$currOutput[] = $currRow[$currIndex];
}
// Append the new reordered row to the output buffer
$output[] = $currOutput;
}
fclose($fh);
print_r($output);
输出:
Array
(
[0] => Array
(
[0] => Header C
[1] => Header A
[2] => Header B
[3] => Header D
)
[1] => Array
(
[0] => c
[1] => a
[2] => b
[3] => d
)
[2] => Array
(
[0] => 3
[1] => 1
[2] => 2
[3] => 4
)
[3] => Array
(
[0] => charlie
[1] => alpha
[2] => bravo
[3] => delta
)
)
我通常将这种东西包装在一个帮助程序中 class 以使其封装和可测试,并保持使用它的代码干净整洁。
我目前正在尝试操作 CSV 文件。我希望能够更改列的顺序。
所以我最初的想法是读取哪个列应该在哪个位置,然后将这些列按顺序放入另一个数组,完成后覆盖原始数组。
遗憾的是,在遍历 csv 时,数组是基于行而不是基于列的。
在 PHP 中有没有一种方法可以像翻转 table 那样改变顺序?
没有内置函数可以执行此操作,您将不得不自己动手。如果您将整个文件读入数组然后对其执行某种转换,那么对 CSV 中的数据执行此类操作可能会导致内存问题,因此最好逐行执行此操作。这样您就可以将行流式传输到一个新文件,而不是将它们全部存储在一个大数组中。
这是一个快速而粗略的解决方案,您可以在其中提供列索引数组来定义新顺序。简单有效。
输入:
Header A,Header B,Header C,Header D
a,b,c,d
1,2,3,4
alpha,bravo,charlie,delta
$fh = fopen('reorder.csv', 'r');
/*
* Create an array with column indices in the order that they
* should appear in the output.
*
* Each column that should appear in the output must be included.
* This is both a feature and a potential gotcha.
*/
$colSpec = [0,3,2,1];
// Output buffer
$output = [];
while($currRow = fgetcsv($fh))
{
// Buffer for our output row
$currOutput = [];
/*
* Loop through the spec array and populate the row output buffer
* using the indices defined there
*/
foreach($colSpec as $currColumnIndex)
{
$currOutput[] = $currRow[$currColumnIndex];
}
// Append the new reordered row to the output buffer
$output[] = $currOutput;
}
fclose($fh);
print_r($output);
输出:
Array
(
[0] => Array
(
[0] => Header A
[1] => Header D
[2] => Header C
[3] => Header B
)
[1] => Array
(
[0] => a
[1] => d
[2] => c
[3] => b
)
[2] => Array
(
[0] => 1
[1] => 4
[2] => 3
[3] => 2
)
[3] => Array
(
[0] => alpha
[1] => delta
[2] => charlie
[3] => bravo
)
)
虽然这不是很直观,但数字索引使得很难从逻辑上理解哪个列要去哪里。如果您的 CSV 有一个 header 行,并且该行中的标签是不可变的,您可以这样做以使其更直观:
/*
* Create an array with header values in the order that they
* should appear in the output.
*
* Each column that should appear in the output must be included.
* This is both a feature and a potential gotcha.
*/
$colSpec = ['Header C', 'Header A', 'Header B', 'Header D'];
// Create a map for column name to actual index in the file
$headerIndexMap = array_flip($colSpec);
// Output buffer
$output = [];
while ($currRow = fgetcsv($fh))
{
// If this is our first row, set up the column mapping
if(empty($output))
{
// Loop through the columns...
foreach($currRow as $index => $currHeaderLabel)
{
/*
* Trim the header value, in case there it leading/trailing whitespace in the data
*/
$currHeaderLabel = trim($currHeaderLabel);
// If this column is in our column spec, set the index in $headerIndexMap
if(array_key_exists($currHeaderLabel, $headerIndexMap))
{
$headerIndexMap[$currHeaderLabel] = $index;
}
}
}
// Buffer for our output row
$currOutput = [];
// Loop through the column spec...
foreach ($colSpec as $currColumn)
{
// Get the actual index of the column from the index map
$currIndex = $headerIndexMap[$currColumn];
// Append the data in the appropriate column to the row output buffer
$currOutput[] = $currRow[$currIndex];
}
// Append the new reordered row to the output buffer
$output[] = $currOutput;
}
fclose($fh);
print_r($output);
输出:
Array
(
[0] => Array
(
[0] => Header C
[1] => Header A
[2] => Header B
[3] => Header D
)
[1] => Array
(
[0] => c
[1] => a
[2] => b
[3] => d
)
[2] => Array
(
[0] => 3
[1] => 1
[2] => 2
[3] => 4
)
[3] => Array
(
[0] => charlie
[1] => alpha
[2] => bravo
[3] => delta
)
)
我通常将这种东西包装在一个帮助程序中 class 以使其封装和可测试,并保持使用它的代码干净整洁。