Transponieren mehrdimensionaler Arrays in PHP

Lesezeit: 9 Minuten

Transponieren mehrdimensionaler Arrays in PHP
Calvin

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 umsetzen flipDiagonally()?

Edit: Das ist keine Hausaufgabe. Ich möchte nur sehen, ob irgendwelche SOers eine kreativere Lösung als die offensichtlichste Route haben. Aber da sich einige Leute darüber beschwert haben, dass dieses Problem zu einfach ist, wie wäre es mit einer allgemeineren Lösung, die mit einem n funktioniertth Dimensions-Array?

dh Wie würden Sie eine Funktion schreiben, damit:

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

?(ps. Ich glaube nicht, dass 12 verschachtelt sind for loops ist in diesem Fall die beste Lösung.)

  • @Calvin Ich weiß, es ist viele Jahre her (11!), Aber … hast du eine Antwort akzeptiert oder nicht? Ist Ihnen aufgefallen, dass die beliebteste Antwort im Grunde falsch ist, weil einzelne Zeilen nicht unterstützt werden [[1,2,…N]]? Schauen Sie sich die Sandbox für die Illustration an: sandbox.onlinephpfunctions.com/code/…

    – Onkeltem

    3. Februar 2020 um 1:22 Uhr

  • Außerdem kann der Splat-Operator keine Zeichenfolgenschlüssel entpacken. Beweis des Fehlers: 3v4l.org/1WSQH …hoppla, mir ist gerade aufgefallen, dass ich das vor über einem Jahr als Antwort auf dieser Seite gesagt habe!

    – mickmackusa

    23. Juni 2020 um 13:20 Uhr


1646982248 2 Transponieren mehrdimensionaler Arrays in PHP
Kodler

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

  • NULL wird als Parameter an array_unshift übergeben, wodurch am Anfang des Arrays ein Wert hinzugefügt wird. Die erste Zeile fügt also NULL als ersten Wert des Arrays ein. Die nächste Zeile ruft array_map mit allen Einträgen von $array als Parameter auf. Es ist also dasselbe wie das Aufrufen von array_map(NULL, $array[0]$array[1]$array[2], usw usw). In der Dokumentation zu array_map gibt es ein Detail: “Eine interessante Verwendung dieser Funktion besteht darin, ein Array von Arrays zu erstellen, was einfach durch die Verwendung von NULL als Name der Callback-Funktion ausgeführt werden kann.”

    – Jeremy Warne

    26. April 2012 um 23:56 Uhr


  • Diese Funktion behält die Indizes nicht, wenn sie vom Typ String sind. Es gibt die transponierte Matrix mit numerischem Index zurück. Die Funktion flipDiagonally funktioniert in diesem Fall einwandfrei. Upvote sowieso für die Einfachheit

    – luso

    24. August 2012 um 14:45 Uhr

  • Dies bricht zusammen, wenn es nur eine Zeile gibt, z. B. transponieren ( [[1,2]]) Erwartet: [[1],[2]]Tatsächlich: [1,2]

    – Chris

    16. März 2015 um 21:13 Uhr

  • sollte eine Beschreibung in der Antwort sein.

    – Awlad Liton

    14. Oktober 2015 um 11:24 Uhr

  • aber warum funktioniert das? Diese Antwort ist für mich völlig undurchsichtig

    – daniel

    26. November 2015 um 12:21 Uhr

Mit 2 Schlaufen.

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

  • Obwohl Codlers Antwort prägnanter ist, denke ich, dass dies eigentlich der bessere Weg ist, weil es so viel klarer ist, was vor sich geht. Wenn sich jemand mit Programmiererfahrung, aber kein PHP-Guru, die beiden Antworten ansehen würde, würde er sofort verstehen, was diese tut, müsste aber das Kleingedruckte der Dokumentation lesen, um der anderen zu folgen. +1

    – Hackartist

    3. Februar 2012 um 23:05 Uhr

  • Im Gegenteil, ich habe festgestellt, dass dies mit nicht numerischen Tasten nicht so gut funktioniert. Zum Beispiel $test = array(array('a'=>1, 'b'=>2,'c'=>3), array(4,5,6), array(7,8,9));: Es erstellt ein Einzelelement-Array für jeden Wert mit einem nicht numerischen Schlüssel. Mit angegebenen Zifferntasten (z. B. $test = array(array(4,5,6), array(11=>1, 12=>2, 13=>3), array(7,8,9));), macht es etwas Seltsames. Während von allen Rechten dies sollte Arbeit, ich denke, wir brauchen eine bessere Lösung!

    – JohannesK

    14. Juli 2014 um 20:01 Uhr


  • @JohnK [0][1] und [2][1] wird werden [1][0] und [1][2]. Es dreht die Schlüssel um. Ich habe Ihre Beispiele ausprobiert und es funktioniert genau wie beabsichtigt. Ich bin mir nicht sicher, was Sie erwartet haben.

    – OIS

    4. August 2014 um 13:45 Uhr

  • Hat jemand die beiden Lösungen profiliert? Wie gut skaliert die Lösung von Codler, wenn count($arr) wirklich hoch ist?

    – Donquijote

    5. Juli 2016 um 15:17 Uhr

  • @donquixote Codlers Lösung ist falsch. Schlecht. Es unterstützt keine assoziativen Arrays und schlägt im trivialen Randfall einer einzelnen Zeile/Spalte fehl: [[a,b,…,z]]. Es muss abgewertet werden, um die Menschen nicht zu verwirren.

    – Onkeltem

    3. Februar 2020 um 1:13 Uhr


Ich denke du meinst das Array transponieren (Spalten werden zu Zeilen, Zeilen werden zu Spalten).

Hier ist eine Funktion, die das 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;
} 

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 hackish und wahrscheinlich nicht die beste Lösung, aber hey, es funktioniert.

Grundsätzlich durchläuft es das Array rekursiv und sammelt die aktuellen Indizes in einem Array.
Sobald es den referenzierten Wert erreicht hat, nimmt es den “Stapel” von Indizes und kehrt ihn um, indem es ihn in das $out-Array einfügt. (Gibt es eine Möglichkeit, die Verwendung des $temp-Arrays zu vermeiden?)

Transponieren mehrdimensionaler Arrays in PHP
seltsam

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],
    ];

Die array_unshift Trick funktionierte NOCH nicht array_map

Also habe ich a codiert array_map_join_array Funktion zum Umgang mit der Zuordnung von Datensatzschlüsseln:

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

Transponieren mehrdimensionaler Arrays in PHP
mickmackusa

Wenn Sie versuchen, die Beispieldaten des OP mit dem Splat-Operator (...), erzeugen Sie:

Schwerwiegender Fehler: Nicht erfasster Fehler: Array mit Zeichenfolgenschlüsseln kann nicht entpackt werden

Nachweisen

Rufen Sie an, um diesen Fehler zu beheben array_values() um die Schlüssel der ersten Ebene vor dem Auspacken 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',
  ),
)

Eine zusätzliche Besonderheit/Überraschung bezüglich der Transponierung mit dieser Technik ist die null Elemente werden generiert, wenn die Subarrays unterschiedliche Größen haben … aber vielleicht nicht dort, wo Sie es erwarten würden.

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, die diese Funktion an den Tag legt (vergleichbar mit der Gepäckabfertigung, die Ihr Gepäck aus dem Bauch des Flugzeugs holt). Die IDs der ursprünglichen Subarray-Werte werden nicht beachtet (und es wäre egal, ob 1, 2& 3 wurden x, y& z); Was auch immer vom Förderband kommt, wird in den niedrigsten verfügbaren Schlitz geworfen.

Dieses Verhalten ist konsistent und zuverlässig beim Liefern einer vollständigen Matrix. EIN foreach() Schleifenalternative liefert nicht nativ null Element aus Subarrays unterschiedlicher Größe, und in den meisten Implementierungen hängt seine 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üssten Sie, wenn Sie sicher sein möchten, dass Sie ALLE Daten aus dem Eingabearray extrahiert haben, eine Additionslogik schreiben, um alle eindeutigen Spalten-IDs an die foreach-Schleife zu liefern.


ps Bevor ich von dieser verkürzten transponierenden Syntax erfuhr, schrieb ich einen hässlicheren, ausführlicheren funktionalen Transposer, der einige Kritik einstecken musste.

1646982248 449 Transponieren mehrdimensionaler Arrays in PHP
José Trindade

Ich wurde mit dem gleichen Problem konfrontiert. Hier ist, was ich herausgefunden habe:

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

  • Dieser Antwort fehlt die einfache englische Erklärung.

    – mickmackusa

    15. März 2020 um 11:59 Uhr

990160cookie-checkTransponieren mehrdimensionaler Arrays in PHP

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy