(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 以使其封装和可测试,并保持使用它的代码干净整洁。