代码之家  ›  专栏  ›  技术社区  ›  Calvin

在PHP中转置多维数组

  •  65
  • Calvin  · 技术社区  · 17 年前

    如何在PHP中翻转90度(转置)多维数组?例如:

    // Start with this array
    $foo = array(
        'a' => array(
           1 => 'a1',
           2 => 'a2',
           3 => 'a3' 
        ),
        'b' => array(
           1 => 'b1',
           2 => 'b2',
           3 => 'b3' 
        ),
        'c' => array(
           1 => 'c1',
           2 => 'c2',
           3 => 'c3' 
        )
    );
    
    $bar = flipDiagonally($foo); // Mystery function
    var_dump($bar[2]);
    
    // Desired output:
    array(3) {
      ["a"]=>
      string(2) "a2"
      ["b"]=>
      string(2) "b2"
      ["c"]=>
      string(2) "c2"
    }
    

    你将如何实施 flipDiagonally()

    编辑:这不是家庭作业。我只想看看是否有SOER有比最明显的路线更具创造性的解决方案。但是,既然有一些人抱怨这个问题太容易了,那么一个更通用的解决方案如何处理n呢

    i、 e.如何编写函数以便:

    $foo[j][k][...][x][y][z] = $bar[z][k][...][x][y][j]
    

    ?(附:我不认为12岁。) for loops 是这种情况下的最佳解决方案。)

    9 回复  |  直到 7 年前
        1
  •  253
  •   mystery Barmar    10 年前
    function transpose($array) {
        array_unshift($array, null);
        return call_user_func_array('array_map', $array);
    }
    

    或者如果您使用的是PHP5.6或更高版本:

    function transpose($array) {
        return array_map(null, ...$array);
    }
    
        2
  •  69
  •   OIS    17 年前

    有两个回路。

    function flipDiagonally($arr) {
        $out = array();
        foreach ($arr as $key => $subarr) {
            foreach ($subarr as $subkey => $subvalue) {
                $out[$subkey][$key] = $subvalue;
            }
        }
        return $out;
    }
    
        3
  •  8
  •   Aziz    17 年前

    我想你指的是阵列 transpose

    这里有一个函数可以帮你实现 (source) :

    function array_transpose($array, $selectKey = false) {
        if (!is_array($array)) return false;
        $return = array();
        foreach($array as $key => $value) {
            if (!is_array($value)) return $array;
            if ($selectKey) {
                if (isset($value[$selectKey])) $return[] = $value[$selectKey];
            } else {
                foreach ($value as $key2 => $value2) {
                    $return[$key2][$key] = $value2;
                }
            }
        }
        return $return;
    } 
    
        4
  •  3
  •   v3.    17 年前

    function transpose($array, &$out, $indices = array())
    {
        if (is_array($array))
        {
            foreach ($array as $key => $val)
            {
                //push onto the stack of indices
                $temp = $indices;
                $temp[] = $key;
                transpose($val, $out, $temp);
            }
        }
        else
        {
            //go through the stack in reverse - make the new array
            $ref = &$out;
            foreach (array_reverse($indices) as $idx)
                $ref = &$ref[$idx];
            $ref = $array;
        }
    }
    
    $foo[1][2][3][3][3] = 'a';
    $foo[4][5][6][5][5] = 'b';
    
    $out = array();
    transpose($foo, $out);
    
    echo $out[3][3][3][2][1] . ' ' . $out[5][5][6][5][4];
    

    基本上,它递归地遍历数组,将数组中的当前指示符累加起来。

        5
  •  2
  •   quazardous    8 年前

    我需要一个支持关联数组的转置函数:

        $matrix = [
            ['one' => 1, 'two' => 2],
            ['one' => 11, 'two' => 22],
            ['one' => 111, 'two' => 222],
        ];
    
        $result = \array_transpose($matrix);
    
        $trans = [
            'one' => [1, 11, 111],
            'two' => [2, 22, 222],
        ];
    

    回去的路上:

        $matrix = [
            'one' => [1, 11, 111],
            'two' => [2, 22, 222],
        ];
    
        $result = \array_transpose($matrix);
    
        $trans = [
            ['one' => 1, 'two' => 2],
            ['one' => 11, 'two' => 22],
            ['one' => 111, 'two' => 222],
        ];
    

    array_unshift 诡计不起作用 array_map ...

    所以我编了一个 array_map_join_array 处理记录键关联的函数:

    /**
     * Similar to array_map() but tries to join values on intern keys.
     * @param callable $callback takes 2 args, the intern key and the list of associated values keyed by array (extern) keys.
     * @param array $arrays the list of arrays to map keyed by extern keys NB like call_user_func_array()
     * @return array
     */
    function array_map_join_array(callable $callback, array $arrays)
    {
        $keys = [];
        // try to list all intern keys
        array_walk($arrays, function ($array) use (&$keys) {
            $keys = array_merge($keys, array_keys($array));
        });
        $keys = array_unique($keys);
        $res = [];
        // for each intern key
        foreach ($keys as $key) {
            $items = [];
            // walk through each array
            array_walk($arrays, function ($array, $arrKey) use ($key, &$items) {
                if (isset($array[$key])) {
                    // stack/transpose existing value for intern key with the array (extern) key
                    $items[$arrKey] = $array[$key];
                } else {
                    // or stack a null value with the array (extern) key
                    $items[$arrKey] = null;
                }
            });
            // call the callback with intern key and all the associated values keyed with array (extern) keys
            $res[$key] = call_user_func($callback, $key, $items);
        }
        return $res;
    }
    

    array_transpose

    function array_transpose(array $matrix)
    {
        return \array_map_join_array(function ($key, $items) {
            return $items;
        }, $matrix);
    }
    
        6
  •  2
  •   mickmackusa Tom Green    7 年前

    如果您试图用splat操作符解压OP的示例数据( ... ),您将生成:

    Proof

    要克服此错误,请调用 array_values() 在解包之前索引一级键。

    var_export(array_map(null, ...array_values($foo)));
    

    输出:

    array (
      0 => 
      array (
        0 => 'a1',
        1 => 'b1',
        2 => 'c1',
      ),
      1 => 
      array (
        0 => 'a2',
        1 => 'b2',
        2 => 'c2',
      ),
      2 => 
      array (
        0 => 'a3',
        1 => 'b3',
        2 => 'c3',
      ),
    )
    

    使用这种技术进行转置的另一个特点/惊喜是 null 当子阵列的大小不同时,将生成元素…但可能不是您预期的位置。

    根据如下示例数据:

    $foo = array(
        'a' => array(
           1 => 'a1',
           2 => 'a2'
        ),
        'b' => array(
           1 => 'b1',
           3 => 'b3' 
        ),
        'c' => array(
           1 => 'c1',
           2 => 'c2',
           3 => 'c3' 
        )
    );
    

    输出为:

    array (
      0 => 
      array (
        0 => 'a1',
        1 => 'b1',
        2 => 'c1',
      ),
      1 => 
      array (
        0 => 'a2',
        1 => 'b3',
        2 => 'c2',
      ),
      2 => 
      array (
        0 => NULL,
        1 => NULL,
        2 => 'c3',
      ),
    )
    

    请注意该功能所表现出的级别小心(与从飞机腹部取出行李的行李处理人员相当)。没有注意到原始子数组值的id(如果 1 , 2 3 x , y ,& z

    foreach() 无效的 元素,在大多数实现中,它访问所有子数组值的能力取决于第一个子数组的长度。

    $foo = array(
        'a' => array(
           1 => 'a1',
           2 => 'a2'
        ),
        'b' => array(
           1 => 'b1',
        ),
        'c' => array(
           1 => 'c1',
           2 => 'c2',
           3 => 'c3' 
        )
    );
    
    foreach (current($foo) as $column => $not_used) {
        $result[] = array_column($foo, $column);
    }
    var_export($result);
    

    输出:

    array (
      0 => 
      array (
        0 => 'a1',
        1 => 'b1',
        2 => 'c1',
      ),
      1 => 
      array (
        0 => 'a2',
        1 => 'c2',
      ),
    )
    

    如上所示,如果要确保从输入数组中提取了所有数据,就必须编写加法逻辑,将所有唯一的列id传递给foreach循环。


    an uglier, more verbose functional transposer that copped some criticism

        7
  •  1
  •   José Trindade    10 年前

    我也遇到了同样的问题。下面是我想到的:

    function array_transpose(array $arr)
    {
        $keys    = array_keys($arr);
        $sum     = array_values(array_map('count', $arr));
    
        $transposed = array();
    
        for ($i = 0; $i < max($sum); $i ++)
        {
            $item = array();
            foreach ($keys as $key)
            {
                $item[$key] = array_key_exists($i, $arr[$key]) ? $arr[$key][$i] : NULL;
            }
            $transposed[] = $item;
        }
        return $transposed;
    }
    
        8
  •  1
  •   mickmackusa Tom Green    5 年前

    以下是 Codler/Andreas's solution 使用关联数组的。有点长但是 无回路 纯功能性:

    <?php
    function transpose($array) {
        $keys = array_keys($array);
        return array_map(function($array) use ($keys) {
            return array_combine($keys, $array);
        }, array_map(null, ...array_values($array)));
    }
    

    例子:

    <?php
    $foo = array(
        "fooA" => [ "a1", "a2", "a3"],
        "fooB" => [ "b1", "b2", "b3"],
        "fooC" => [ "c1", "c2", "c3"]
    );
    
    print_r( transpose( $foo ));
    // Output like this:
    Array (
        [0] => Array (
            [fooA] => a1
            [fooB] => b1
            [fooC] => c1
        )
    
        [1] => Array (
            [fooA] => a2
            [fooB] => b2
            [fooC] => c2
        )
    
        [2] => Array (
            [fooA] => a3
            [fooB] => b3
            [fooC] => c3
        )
    );
    
        9
  •  1
  •   Mehedi Hasan    5 年前

    我们可以用两个foreach。移动一个阵列和另一个阵列以创建新阵列

    $foo = array(
        'a' => array(
           1 => 'a1',
           2 => 'a2',
           3 => 'a3' 
        ),
        'b' => array(
           1 => 'b1',
           2 => 'b2',
           3 => 'b3' 
        ),
        'c' => array(
           1 => 'c1',
           2 => 'c2',
           3 => 'c3' 
        )
    );
    
    $newFoo = [];
    foreach($foo as $a => $k){
       foreach($k as $i => $j){
           $newFoo[$i][]= $j;
       }
    }
    

    检查输出

    echo "<pre>";
    print_r($newFoo);
    echo "</pre>";
    
        10
  •  0
  •   Carsten Massmann    8 年前

    在我开始之前,我想说 再次感谢@quazardus发布了他转换任意二维关联(或非关联)数组的通用解决方案!

    由于我习惯于尽可能简洁地编写代码,所以我进一步“最小化”了他的代码。这将 很有可能 符合每个人的口味。但万一有人对此感兴趣,以下是我对他的解决方案的看法:

    function arrayMap($cb, array $arrays) // $cb: optional callback function
    {   $keys = [];
        array_walk($arrays, function ($array) use (&$keys) 
                            { $keys = array_merge($keys, array_keys($array)); });
        $keys = array_unique($keys); $res = [];
        foreach ($keys as $key) {
          $items = array_map(function ($arr) use ($key)
                             {return isset($arr[$key]) ? $arr[$key] : null; },$arrays);
          $res[$key] = call_user_func(
            is_callable($cb) ? $cb 
                             : function($k, $itms){return $itms;},
            $key, $items);
        }
        return $res;
    }
    

    array_map() ,当你打电话的时候

    arrayMap(null,$b);
    

        11
  •  0
  •   th3pirat3    7 年前

    function transposeCsvData($data)
    {
        $ct=0;
        foreach($data as $key => $val)
        {
            //echo count($val);
            if($ct< count($val))
                $ct=count($val);
            }
        //echo $ct;
        $blank=array_fill(0,$ct,array_fill(0,count($data),null));
        //print_r($blank);
    
        $retData = array();
        foreach ($data as $row => $columns)
        {
            foreach ($columns as $row2 => $column2) 
            {
                $retData[$row2][$row] = $column2;
                }
            }
        $final=array();
        foreach($retData as $k=>$aval)
        { 
            $final[]=array_replace($blank[$k], $aval);
           }
        return $final;
        }
    

    测试和输出参考: https://tutes.in/how-to-transpose-an-array-in-php-with-irregular-subarray-size/

        12
  •  0
  •   Rahul    7 年前

    这是实现这一目标的最佳途径,

    function flipDiagonally($foo){
        $temp = [];
        array_walk($foo, function($item,$key) use(&$temp){
            foreach($item as $k => $v){
                $temp[$k][$key] = $v;     
            }
        });
        return $temp;
    }
    $bar = flipDiagonally($foo); // Mystery function
    

    Demo

        13
  •  -2
  •   MrCharif    8 年前
    <?php
    
    $tableau_init = [
        [
            "prenom" => "med",
            "age" => 1
        ],
        [
            "prenom" => "hassan",
            "age" => 2
        ],
        [
            "prenom" => "ali",
            "age" => 3
        ]
    ];
    
    function transpose($tableau){
        $out = array();
    
        foreach ($tableau as $key => $value){
            foreach ($value as $subKey => $subValue){
                $out[$subKey][$key] = $subValue;
            }
        }
    
        echo json_encode($out);
    }
    
    transpose($tableau_init);