Comment inverseriez-vous 90 degrés (transposons) un tableau multidimensionnel en PHP? Par exemple:
// 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"
}
Comment mettriez-vous en œuvre flipDiagonally()
?
Edit: ce n'est pas un devoir. Je veux juste voir si les SO ont une solution plus créative que la voie la plus évidente. Mais puisque quelques personnes se sont plaintes de ce problème trop facile, qu’en est-il d’une solution plus générale qui fonctionne avecth tableau de dimension?
comment écririez-vous une fonction pour que:
$foo[j][k][...][x][y][z] = $bar[z][k][...][x][y][j]
? ps. Je ne pense pas que 12 for loops
imbriqué soit la meilleure solution dans ce cas.)
function transpose($array) {
array_unshift($array, null);
return call_user_func_array('array_map', $array);
}
Ou si vous utilisez PHP 5.6 ou une version ultérieure:
function transpose($array) {
return array_map(null, ...$array);
}
Avec 2 boucles.
function flipDiagonally($arr) {
$out = array();
foreach ($arr as $key => $subarr) {
foreach ($subarr as $subkey => $subvalue) {
$out[$subkey][$key] = $subvalue;
}
}
return $out;
}
Je pense que vous faites référence au tableau transpose (les colonnes deviennent des lignes, les lignes deviennent des colonnes).
Voici une fonction qui le fait pour vous (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;
}
Transposer un tableau à N dimensions:
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];
Vraiment hack, et probablement pas la meilleure solution, mais bon ça marche.
Fondamentalement, il parcourt le tableau de manière récursive, accumulant les indicateurs actuels dans un tableau.
Une fois que la valeur référencée est atteinte, il prend la "pile" d'index et l'inverse, la plaçant dans le tableau $ out. (Y a-t-il un moyen d'éviter l'utilisation du tableau $ temp?)
Voici une variante de la solution Codler/Andreas qui fonctionne avec les tableaux associatifs. Un peu plus long mais sans boucle:
<?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)));
}
Exemple:
<?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
)
);
J'ai été confronté au même problème. Voici ce que je suis venu avec:
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;
}
J'avais besoin d'une fonction de transposition prenant en charge le tableau associatif:
$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],
];
Et le chemin du retour:
$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],
];
L'astuce array_unshift
n'a pas fonctionné NOR le array_map
...
J'ai donc codé une fonction array_map_join_array
pour gérer l'association des clés d'enregistrement:
/**
* 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;
}
et array_transpose
est devenu évident:
function array_transpose(array $matrix)
{
return \array_map_join_array(function ($key, $items) {
return $items;
}, $matrix);
}
Utiliser comme ça
<?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);
?>
Résultat:
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);
Essayez comme ça
Si vous essayez de décompresser les exemples de données du PO avec l'opérateur Splat (...
), vous allez générer:
Erreur fatale: Erreur non capturée: impossible de décompresser le tableau avec des clés de chaîne
Pour surmonter cette erreur, appelez array_values()
pour indexer les clés de premier niveau avant de décompresser.
var_export(array_map(null, ...array_values($foo)));
Sortie:
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',
),
)
Une caractéristique/surprise supplémentaire concernant la transposition avec cette technique est que des éléments null
seront générés lorsque les sous-tableaux auront des tailles différentes ... mais peut-être pas où vous pourriez vous attendre.
À partir d'un exemple de données comme ceci
$foo = array(
'a' => array(
1 => 'a1',
2 => 'a2'
),
'b' => array(
1 => 'b1',
3 => 'b3'
),
'c' => array(
1 => 'c1',
2 => 'c2',
3 => 'c3'
)
);
La sortie est:
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',
),
)
Notez le niveau de soin affiché par la fonction (comparable aux bagagistes qui sortent vos bagages du ventre de l’avion). Les identifiants des valeurs initiales des sous-tableaux ne sont pas pris en compte (et peu importe si 1
, 2
et 3
étaient x
, y
, & z
); tout ce qui sort de la bande transporteuse est jeté dans le logement disponible le plus bas.
Ce comportement est cohérent et fiable dans la livraison d'une matrice complète. Une variante de boucle foreach()
ne livrera pas en natif l'élément null
à partir de sous-matrices de tailles différentes et, dans la plupart des implémentations, sa capacité à accéder à toutes les valeurs de sous-matrice dépend de la longueur du premier sous-tableau.
$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);
Sortie:
array (
0 =>
array (
0 => 'a1',
1 => 'b1',
2 => 'c1',
),
1 =>
array (
0 => 'a2',
1 => 'c2',
),
)
Comme indiqué ci-dessus, si vous voulez être sûr d'avoir extrait TOUTES les données du tableau en entrée, vous devez écrire une logique d'addition pour fournir tous les identifiants de colonne uniques à la boucle foreach.
p.s. Avant d’apprendre cette syntaxe de transposition abrégée, j’ai écrit un transposeur fonctionnel plus laid, plus bavard qui a fait l’objet de critiques .
Voici une méthode array_walk pour y parvenir,
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
Démo .
C’est une autre façon de faire exactement la même chose que la réponse de @codler. Je devais vider quelques tableaux en csv, alors j’utilisais la fonction suivante:
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;
}
Référence de test et de sortie: https://tutes.in/how-to-transpose-an-array-in-php-with-irregular-subarray-size/