PHP-как перевернуть строки и столбцы 2D-массива

обычно я бы спросил, Как превратить что-то вроде этого:

1      2        3
4      5        6
7      8        9
10    11       12

в:

1   4   7   10
2   5   8   11
3   6   9   12

но на самом деле я хочу превратить его в это:

1   5   9
2   6   10
3   7   11
4   8   12

другими словами, Я хочу перевернуть строки и столбцы, но сохранить ту же "ширину" и "высоту" нового массива. Я застрял на этом больше часа.

это функция, которую я использую, чтобы сделать обычный "флип" (первый пример):

function flip($arr)
{
    $out = array();

    foreach ($arr as $key => $subarr)
    {
            foreach ($subarr as $subkey => $subvalue)
            {
                 $out[$subkey][$key] = $subvalue;
            }
    }

    return $out;
}

9 ответов


просто пройдите массив в правильном порядке. Предполагая, что у вас относительно небольшие массивы, самое простое решение-просто создать новый массив во время этой прогулки.

решение будет иметь вид:

$rows = count($arr);
$cols = count($arr[0]); // assumes non empty matrix
$ridx = 0;
$cidx = 0;

$out = array();

foreach($arr as $rowidx => $row){
    foreach($row as $colidx => $val){
        $out[$ridx][$cidx] = $val;
        $ridx++;
        if($ridx >= $rows){
            $cidx++;
            $ridx = 0;
        }
    }
}

function flip_row_col_array($array) {
    $out = array();
    foreach ($array as  $rowkey => $row) {
        foreach($row as $colkey => $col){
            $out[$colkey][$rowkey]=$col;
        }
    }
    return $out;
}

мне пришлось написать это, чтобы инвертировать массив индексированных массивов имен. Это очень полезно для печати PHP-массива как html-таблицы, так как он даже заполняет отсутствующие элементы нулями, поэтому количество одинаково для всех строк html-таблицы.

  /**
  * Inverses a two dimentional array.
  * The second dimention can be <b>name indexed</b> arrays, that would be preserved.
  * This function is very useful, for example, to print out an html table
  * from a php array.
  * It returns a proper matrix with missing valus filled with null.
  *
  * @param type $arr input 2d array where second dimention can be. <b>name indexed</b>
  * arrays.
  * @return 2d_array returns a proper inverted matrix with missing values filled with
  * nulls
  * @author Nikolay Kitsul
  */
 public static function array_2D_inverse($arr) {
     $out = array();
     $ridx = 0;
     foreach ($arr as $row) {
         foreach ($row as $colidx => $val) {
             while ($ridx > count($out[$colidx]))
                 $out[$colidx][] = null;
             $out[$colidx][] = $val;
         }
         $ridx++;
     }
     $max_width = 0; 
     foreach($out as $v)
          $max_width = ($max_width < count($v)) ? count($v) : $max_width;
     foreach($out as $k => $v){
         while(count($out[$k]) < $max_width)
             $out[$k][] = null;
     }
     return $out;
 }

что нужно:

function flip($array) {
    array_unshift($array, null);
    return call_user_func_array('array_map', $array);
}

здесь вы идете. Это работает. :)



$input1 = array(1,2,3);
$input2 = array(4,5,6);
$input3 = array(7,8,9);
$input4 = array(10,11,12);

$input = array($input1,$input2,$input3,$input4);

echo "\n input array";print_r($input);

// flipping matrices
$output = array();
$intern = array();

for($row=0; $row lt 4; $row++)
    for($col=0;$col lt 3;$col++)
        $intern[] = $input[$row][$col];

echo "\n intern ";print_r($intern);

// nesting the array
$count = 0;
$subcount = 0;

foreach($intern as $value)
{

    $output[$count][$subcount] = $value;
    $count++;

    if($subcount == 3)
    {
        break;
    }

    if($count == 4)
    {
        $count = 0;
        $subcount++;
    }


}


echo "\n final output ";print_r($output);

Я разработал этот код, частично основанный на решении, найденном здесь, чтобы сгладить многомерные массивы.

надеюсь, что это помогает!

/**
 *
 * http://stackoverflow.com/questions/2289475/converting-php-array-of-arrays-into-single-array
 * @param array $array
 * @return array
 */
function arrayFlatten(array $array)
{
    $flatten = array();
    array_walk_recursive($array, function($value) use(&$flatten)
    {
        $flatten[] = $value;
    });

    return $flatten;
}

/**
 *
 *  Reorders an array to put the results ordered as a "N", instead of a "Z"  
 *
 * @static
 * @param $array Array to be ordered
 * @param $columns Number of columns of the "N"
 * @return void
 */
function ZOrderToNOrder($array, $columns)
{
    $maxRows = ceil(count($array) / $columns);
    $newArray = array();
    $colCounter = 0;
    $rowCounter = 0;
    foreach ($array as $element)
    {
        $newArray[$rowCounter][] = $element;
        $rowCounter++;
        if ($rowCounter == $maxRows)
        {
            $colCounter++;
            $rowCounter = 0;
        }
    }

    return arrayFlatten($newArray);
}

falvarez, функция ZOrderToNOrder работает неправильно, когда один или несколько столбцов имеют еще один элемент, что другие столбцы (другое > 1).

Я думаю, что этот код исправить это:

public static function ZOrderToNOrder($array, $columns) {
    $numElements = count($array);

    $maxRows = array();
    for ($i = 0; $i < $columns; $i++) {
        $maxRows[$i] = intval(ceil(($numElements - $i) / $columns));
    }

    $newArray = array();

    $rowCounter = 0;
    $colCounter = 0;
    foreach ($array as $element) {
        $newArray[$rowCounter][$colCounter] = $element;
        $rowCounter++;
        if ($rowCounter === $maxRows[$colCounter]) {
            $rowCounter = 0;
            $colCounter++;
        }
    }

    return self::arrayFlatten($newArray);
}

С уважением,

Армандо


измененная версия" принятого " ответа, которая работает намного лучше IMHO:

function array2DFlip($arr) {
 if(!is_array($arr) || count($arr) < 1 || !isset($arr[0])) return array();

 $out = array();

 foreach($arr as $row_id => $row){
    foreach($row as $col_id => $val){
        $out[$col_id][$row_id] = $val;
    }
 }

 return $out;
}

получил этот простой:

$matrix = [
  [1, 2, 3],
  [1, 2, 3],
  [1, 2, 3],
];

$flipped = array_map(function($col, $i) use($matrix){
  return array_map(function($row) use($matrix, $i){
    return $row[$i];
  }, $matrix);
}, $matrix, array_keys($matrix));