Wie würden Sie ein mehrdimensionales Array in PHP um 90 Grad drehen (transponieren)? Zum Beispiel:
// 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"
}
Wie würden Sie implementieren flipDiagonally()
?
Bearbeiten: Dies ist keine Hausaufgabe. Ich möchte nur sehen, ob SOer eine kreativere Lösung haben als der naheliegendste Weg. Aber da sich einige Leute darüber beschwert haben, dass dieses Problem zu einfach ist, was ist mit einer allgemeineren Lösung, die mit einem Array der n- ten Dimension funktioniert ?
dh wie würden Sie eine Funktion schreiben, damit:
$foo[j][k][...][x][y][z] = $bar[z][k][...][x][y][j]
? (ps. Ich denke nicht, dass 12 verschachtelt for loops
die beste Lösung in diesem Fall ist.)
php
arrays
higher-order-functions
Calvin
quelle
quelle
Antworten:
function transpose($array) { array_unshift($array, null); return call_user_func_array('array_map', $array); }
Oder wenn Sie PHP 5.6 oder höher verwenden:
function transpose($array) { return array_map(null, ...$array); }
quelle
Mit 2 Schleifen.
function flipDiagonally($arr) { $out = array(); foreach ($arr as $key => $subarr) { foreach ($subarr as $subkey => $subvalue) { $out[$subkey][$key] = $subvalue; } } return $out; }
quelle
$test = array(array('a'=>1, 'b'=>2,'c'=>3), array(4,5,6), array(7,8,9));
: Es wird für jeden Wert ein Einzelelement-Array mit einem nicht numerischen Schlüssel erstellt. Mit bestimmten Zifferntasten (z. B.$test = array(array(4,5,6), array(11=>1, 12=>2, 13=>3), array(7,8,9));
) macht es etwas seltsam. Obwohl dies auf jeden Fall funktionieren sollte , denke ich, dass wir eine bessere Lösung brauchen!Ich denke, Sie beziehen sich auf die Array- Transponierung (Spalten werden zu Zeilen, Zeilen werden zu Spalten).
Hier ist eine Funktion, die dies für Sie erledigt (Quelle) :
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; }
quelle
Transponieren eines N-dimensionalen Arrays:
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];
Wirklich hackisch und wahrscheinlich nicht die beste Lösung, aber hey, es funktioniert.
Grundsätzlich durchläuft es das Array rekursiv und akkumuliert die aktuellen Anzeigen in einem Array.
Sobald es den referenzierten Wert erreicht hat, nimmt es den "Stapel" von Indizes und kehrt ihn um und fügt ihn in das $ out-Array ein. (Gibt es eine Möglichkeit, die Verwendung des $ temp-Arrays zu vermeiden?)
quelle
Ich brauchte eine Transponierungsfunktion mit Unterstützung für assoziatives Array:
$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], ];
Und der Rückweg:
$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], ];
Der
array_unshift
Trick hat weder funktioniert nocharray_map
...Also habe ich eine
array_map_join_array
Funktion für die Zuordnung von Datensatzschlüsseln codiert :/** * 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; }
und
array_transpose
wurde offensichtlich:function array_transpose(array $matrix) { return \array_map_join_array(function ($key, $items) { return $items; }, $matrix); }
quelle
Ich wurde mit dem gleichen Problem konfrontiert. Folgendes habe ich mir ausgedacht:
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; }
quelle
Wenn Sie versuchen, die Beispieldaten des OP mit dem splat-Operator (
...
) zu entpacken , generieren Sie:Beweis
Um diesen Fehler
array_values()
zu beheben, rufen Sie auf, um die Schlüssel der ersten Ebene vor dem Entpacken zu indizieren.var_export(array_map(null, ...array_values($foo)));
Ausgabe:
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', ), )
Ein zusätzliches Merkmal / eine Überraschung beim Transponieren mit dieser Technik ist, dass
null
Elemente generiert werden, wenn die Subarrays unterschiedliche Größen haben ... aber möglicherweise nicht dort, wo Sie es erwarten.Aus Beispieldaten wie diesen:
$foo = array( 'a' => array( 1 => 'a1', 2 => 'a2' ), 'b' => array( 1 => 'b1', 3 => 'b3' ), 'c' => array( 1 => 'c1', 2 => 'c2', 3 => 'c3' ) );
Die Ausgabe ist:
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', ), )
Beachten Sie die Sorgfalt der Funktion (vergleichbar mit den Gepäckabfertigern, die Ihr Gepäck aus dem Bauch des Flugzeugs nehmen). Es gibt keine Aufmerksamkeit auf die ursprünglichen Werte Subarray Ide (und es würde keine Rolle , ob
1
,2
u3
warenx
,y
uz
); Was auch immer vom Förderband kommt, wird in den niedrigsten verfügbaren Schlitz geworfen.Dieses Verhalten ist konsistent und zuverlässig bei der Bereitstellung einer vollständigen Matrix. Eine
foreach()
Schleifenalternative liefert nicht nativnull
Elemente aus Subarrays unterschiedlicher Größe, und in den meisten Implementierungen hängt ihre Fähigkeit, auf alle Subarray-Werte zuzugreifen, von der Länge des ersten Subarrays ab.$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);
Ausgabe:
array ( 0 => array ( 0 => 'a1', 1 => 'b1', 2 => 'c1', ), 1 => array ( 0 => 'a2', 1 => 'c2', ), )
Wie oben gezeigt, müssen Sie, wenn Sie sicherstellen möchten, dass Sie ALLE Daten aus dem Eingabearray extrahiert haben, eine Additionslogik schreiben, um alle eindeutigen Spalten-IDs an die foreach-Schleife zu senden.
ps Bevor ich von dieser Kurztransponierungssyntax erfuhr, schrieb ich einen hässlicheren, ausführlicheren funktionalen Transposer, der einige Kritik auf sich zog .
quelle
Hier ist eine Variation der Codler / Andreas-Lösung , die mit assoziativen Arrays funktioniert. Etwas länger aber
schleifenlosrein funktional:<?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))); }
Beispiel:
<?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 ) );
quelle
Wir können dies tun, indem wir Two foreach verwenden. Reisen ein Array und ein weiteres Array neues Array erstellen
wie folgt aus :
$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; } }
Überprüfen Sie die Ausgabe
echo "<pre>"; print_r($newFoo); echo "</pre>";
quelle
Bevor ich beginne, würde Ich mag sagen , Dank wieder @quazardus für seine verallgemeinerte Lösung für tranposing zwei beliebige dimenional assoziativ (oder nicht assoziative) Arrays veröffentlichen!
Da ich es mir zur Gewohnheit gemacht habe, meinen Code so knapp wie möglich zu schreiben, habe ich seinen Code ein wenig weiter "minimiert". Dies wird sehr wahrscheinlich nicht jedermanns Geschmack sein. Aber nur für den Fall, dass jemand interessiert sein sollte, hier ist meine Sicht auf seine Lösung:
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; }
Jetzt analog zur PHP-Standardfunktion
array_map()
, wenn Sie aufrufenarrayMap(null,$b);
Sie erhalten die gewünschte transponierte Matrix.
quelle
$keys = array_keys(array_merge(...array_values($arrays)));
Ein Sprachkonstrukt hat eine geringere Komplexität und eine noch bessere Leistung.Dies ist eine weitere Möglichkeit, genau das Gleiche zu tun, was die Antwort von @codler tut. Ich musste einige Arrays in csv sichern, damit ich die folgende Funktion verwendete:
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; }
Test- und Ausgabereferenz: https://tutes.in/how-to-transpose-an-array-in-php-with-irregular-subarray-size/
quelle
Hier ist array_walk Weg, um dies zu erreichen:
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 .
quelle
<?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);
Versuchen Sie es so
quelle