Как бы вы перевернули 90-градусный (транспонированный) многомерный массив в PHP? Например:
// 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()
?
Изменить: это не домашнее задание. Я просто хочу посмотреть, есть ли у любого SOers более креативное решение, чем самый очевидный маршрут. Но так как некоторые люди жаловались на то, что эта проблема слишком легка, а что касается более общего решения, которое работает с n- м размерным массивом?
т.е. как бы вы написали функцию так, чтобы:
$foo[j][k][...][x][y][z] = $bar[z][k][...][x][y][j]
? (ps. Я не думаю, что 12 вложенных for loops
– лучшее решение в этом случае.)
function transpose($array) { array_unshift($array, null); return call_user_func_array('array_map', $array); }
Или если вы используете PHP 5.6 или новее:
function transpose($array) { return array_map(null, ...$array); }
С 2 циклами.
function flipDiagonally($arr) { $out = array(); foreach ($arr as $key => $subarr) { foreach ($subarr as $subkey => $subvalue) { $out[$subkey][$key] = $subvalue; } } return $out; }
Я думаю, вы имеете в виду транспонирование массива (столбцы становятся строками, строки становятся столбцами).
Вот функция, которая делает это для вас (источник) :
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; }
Транспонирование N-мерного массива:
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];
Действительно взломать и, вероятно, не лучшее решение, но эй это работает.
В основном он рекурсивно пересекает массив, накапливая текущие знаки в массиве.
Как только он достигает ссылочного значения, он принимает «стек» индексов и меняет его, помещая его в массив $ out. (Есть ли способ избежать использования массива $ temp?)
Я столкнулся с той же проблемой. Вот что я придумал:
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; }
Мне нужна была функция транспонирования с поддержкой ассоциативного массива:
$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
не работает NOR 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); }
Используйте это
<?php $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' ) ); echo "<pre>"; $i=0; foreach ($foo as $val) { $i++; $array[$i] = array_column($foo, $i); } print_r($array); ?>
Результат:
Array ( [1] => Array ( [0] => a1 [1] => b1 [2] => c1 ) [2] => Array ( [0] => a2 [1] => b2 [2] => c2 ) [3] => Array ( [0] => a3 [1] => b3 [2] => c3 ) )
<?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);
Попробуйте это
Прежде чем начать, я хотел бы еще раз поблагодарить @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; }
Теперь, аналогично стандартной функции PHP array_map()
, когда вы вызываете
arrayMap(null,$b);
вы получите желаемую транспонированную матрицу.