在 PHP 中调换多维数组

如何在 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这个维数组的更通用的解决方案怎么样呢?

例如,如何编写一个函数以便:

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

我不认为12个嵌套的 for loops是这种情况下的最佳解决方案

51930 次浏览

有两个循环。

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 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);
}

我也遇到了同样的问题,这是我想到的:

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的把戏没有工作,也没有 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);
}

在我开始之前,我想说 谢谢再次@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);

你会得到所需的转置矩阵。

这是另一种与@codler 的回答完全相同的方法。我必须在 csv 中转储一些数组,所以我使用了以下函数:

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/

这里有一种 array _ walk 方法来实现这一点,

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

演示。

下面是 Codler/Andreas 的解决方案的一个变体,它可以处理关联数组,比 没有循环稍长一些,但是纯粹是功能性的:

<?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
)
);

我们可以通过使用 Two foreach 来实现这一点,通过遍历一个数组和另一个数组来创建新的数组 < br > ,如下所示:

$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>";

Codler 的答案不适用于单行矩阵(例如 [[1,2]]) ,也不适用于空矩阵([]) ,它必须是特殊情况下的:

function transpose(array $matrix): array {
if (!$matrix) return [];
return array_map(count($matrix) == 1 ? fn ($x) => [$x] : null, ...$matrix);
}

(注意: PHP 7.4 + 语法,很容易适应旧版本)