【问题标题】:(PHP) CSV Change column order(PHP) CSV 更改列顺序
【发布时间】:2021-09-23 12:25:39
【问题描述】:

我目前正在尝试操作 CSV 文件。我希望能够更改列的顺序。

所以我最初的想法是读取哪一列应该在哪个位置,然后将这些列按顺序放入另一个数组中,并在完成后覆盖原始数组。

遗憾的是,在遍历 csv 时,数组是基于行而不是基于列的。

PHP 中有没有一种方法可以像翻转表格一样改变顺序?

【问题讨论】:

  • 您可以只编辑 .csv 文件本身吗?还是您更喜欢通过 PHP 来完成?
  • 我需要在商店软件中导入 csv 文件,我有许多不同的 csv 文件。手动更改它们既繁琐又耗时。所以我想构建一个小脚本,我可以在其中重新排列 collums 甚至删除一些。 TLDR.:是,但不是
  • 明白了,是的,这有点难。我会多看几遍;但我创建了一个function that assigns the column name as the keys in an array,不确定这是否有帮助,但值得一试,因为它可能会给你一个关于如何去创建你需要的东西的概念
  • 更难的是如何决定你想要的列的顺序。假设你不希望每个不同的文件有相同的顺序。我可以看到只是颠倒所说的顺序,但根据给定的格式有效地重新排序它们对 me 来说似乎是不合理的(当然我可能是错的)。如果您只使用我在上面提供的功能,那么订单将无关紧要,不是吗?因为您可以使用键名调用您想要的任何列,而无需担心顺序。
  • 我使用了下面的答案,效果很好。完成后我可能会在这里发布我的解决方案

标签: php arrays csv col


【解决方案1】:

没有内置函数可以做到这一点,您必须自己动手。如果您将整个文件读入数组然后对其执行某种转换,则对 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 有一个标题行,并且该行中的标签是不可变的,您可以执行以下操作以使其更直观:

/*
 * 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
        )

)

我通常将这类东西包装在一个帮助类中,使其可封装和可测试,并保持使用它的代码整洁。

【讨论】:

  • 这正好解决了我的问题,非常好。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
  • 2011-04-09
  • 2011-07-24
  • 1970-01-01
相关资源
最近更新 更多