Wie wird ein mehrdimensionales Array abgeflacht?

259

Ist es in PHP möglich, ein (zweidimensionales) Array ohne Verwendung von Rekursion oder Referenzen zu reduzieren?

Ich interessiere mich nur für die Werte, damit die Schlüssel ignoriert werden können. Ich denke in den Zeilen von array_map()und array_values().

Alix Axel
quelle
17
Warum Rekursion vermeiden?
JorenB
5
Dupe (meistens) stackoverflow.com/questions/526556/…
cletus
4
Sie können nicht mit allen Elementen eines beliebig tiefen Arrays ohne Rekursion etwas tun (Sie können es als Iteration tarnen, aber Kartoffel, Potahto.) Wenn Sie nur vermeiden möchten, den Code für die Rekursionsbehandlung selbst zu schreiben, verwenden Sie dk2.php.net/ manual / de / function.array-walk-recursive.php mit einem Rückruf, der das Element einem verfügbaren Array hinzufügt (verwenden Sie global, den Parameter userdata, ordnen Sie alles in eine Klasse ein und verweisen Sie auf $ this usw.)
Michael Madsen
@JorenB: Ich würde gerne sehen, dass eine Implementierung archiviert werden kann.
Alix Axel
Schauen Sie sich die Abflachungsfunktion von Nspl an . Sie können damit auch eine Tiefe angeben.
Ihor Burlachenko

Antworten:

276

Sie können die Standard-PHP-Bibliothek (SPL) verwenden , um die Rekursion "auszublenden".

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));
foreach($it as $v) {
  echo $v, " ";
}

druckt

1 2 3 4 5 6 7 8 9 
VolkerK
quelle
351
Bin ich der einzige, der denkt, dass 'RecursiveIteratorIterator' ein alberner Name ist?
Nilamo
45
Es ist eher "logisch" als "eingängig". Nicht alles kann einen fantastischen Namen wie JOGL, Knol oder Azure haben :-)
VolkerK
7
Dies funktioniert nicht für leere Arrays als Kinder. Sie werden als Eltern zurückgegeben.
hakre
45
iterator_to_array($it, false)vermeidet die Notwendigkeit für die foreach.
Alix Axel
3
Aufbauend auf dem, was andere präsentierten, konnte ich diesen kleinen Helfer herstellen: Ich function flatten($arr){ $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr)); return iterator_to_array($it, true); }hoffe, das hilft anderen.
Mike S.
295

Ab PHP 5.3 scheint die kürzeste Lösung array_walk_recursive()die neue Closures-Syntax zu sein:

function flatten(array $array) {
    $return = array();
    array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
    return $return;
}
zu viel php
quelle
33
Wenn Sie Schlüssel möchten, Funktion flatten (Array $ Array) {$ return = Array (); array_walk_recursive ($ array, function ($ a, $ b) use (& $ return) {$ return [$ b] = $ a;}); return $ return; }
Brendon-Van-Heyzen
Kannst du dies umschreiben, um es mit PHP 5.2 zu verwenden?
Alex
2
@ Alex leider benötigen Sie die useSyntax, damit dies funktioniert, array_walk_recursiveda es den optionalen $userdataParameter nicht als Referenz akzeptiert
Tim Seguine
1
Sieht so aus, als würde es für solche Arrays gut funktionieren -> ideone.com/DsmApP Aber nicht für solche -> ideone.com/5Kltva Oder bin ich es?
Sebastian Piskorski
2
@Sebastian Piskorski, weil Ihre Werte wie Schlüssel behandelt werden. Sobald Sie also Ihr eigenes Schlüssel => Wertepaar in ein Array einfügen, werden Ihre Array-Werte an der ersten Indexposition wie Schlüssel ohne Werte behandelt, und weil Schlüssel haben Um eindeutig zu sein, wenn zwei Schlüssel übereinstimmen, werden Ihre Werte demselben Schlüssel hinzugefügt. Eine einfache Lösung wäre, zuerst das Array zu sortieren. Dies ist ein Verhalten, das PHP innewohnt.
Martyn Shutt
92

Lösung für zweidimensionales Array

Bitte versuchen Sie dies:

$array  = your array

$result = call_user_func_array('array_merge', $array);

echo "<pre>";
print_r($result);

EDIT: 21-Aug-13

Hier ist die Lösung, die für mehrdimensionale Arrays funktioniert:

function array_flatten($array) {
    $return = array();
    foreach ($array as $key => $value) {
        if (is_array($value)){
            $return = array_merge($return, array_flatten($value));
        } else {
            $return[$key] = $value;
        }
    }

    return $return;
}

$array  = Your array

$result = array_flatten($array);

echo "<pre>";
print_r($result);

Ref: http://php.net/manual/en/function.call-user-func-array.php

Prasanth Bendra
quelle
Vielen Dank, der erste arbeitete an einem Array, das ich von PDO erhalten hatte, während die anderen Lösungen dies nicht taten.
JAL
7
Dies ist eine schlechte Strategie. call_user_func_array('array_merge', [])(Beachten Sie das leere Array) gibt null zurück und löst einen PHP-Warnfehler aus. Es ist eine clevere Lösung, wenn Sie sicher sind, dass Ihr Array nicht leer ist, aber das ist keine verbreitete Annahme, die viele machen können.
Ziege
Das OP forderte ausdrücklich nicht rekursive Lösungen.
Élektra
Wow, coole 2d Flattern! Aber um eine Benachrichtigung zu verhindern, verwenden Sie einfach$result = $array ?call_user_func_array('array_merge', $array) : [];
Alexander Goncharov
cool bruh, aber hast du nicht zufällig eine gegenfunktion array-deflatten?
FantomX1
64

In PHP 5.6 und höher können Sie zweidimensionale Arrays mit array_mergereduzieren, nachdem Sie das äußere Array mit dem ...Operator entpackt haben . Der Code ist einfach und klar.

array_merge(...$a);

Dies funktioniert auch mit der Sammlung von assoziativen Arrays.

$a = [[10, 20], [30, 40]];
$b = [["x" => "X", "y" => "Y"], ["p" => "P", "q" => "Q"]];

print_r(array_merge(...$a));
print_r(array_merge(...$b));

Array
(
    [0] => 10
    [1] => 20
    [2] => 30
    [3] => 40
)
Array
(
    [x] => X
    [y] => Y
    [p] => P
    [q] => Q
)

Es funktioniert jedoch nicht, wenn das äußere Array nicht numerische Schlüssel enthält. In diesem Fall müssen Sie array_valueszuerst anrufen .

$c = ["a" => ["x" => "X", "y" => "Y"], "b" => ["p" => "P", "q" => "Q"]];
print_r(array_merge(...array_values($c)));

Array
(
    [x] => X
    [y] => Y
    [p] => P
    [q] => Q
)

Update: Basierend auf einem Kommentar von @MohamedGharib

Dies löst einen Fehler aus, wenn das äußere Array leer ist, da array_mergees mit null Argumenten aufgerufen würde. Dies kann vermieden werden, indem als erstes Argument ein leeres Array hinzugefügt wird.

array_merge([], ...$a);
Joyce Babu
quelle
1
Dies funktioniert NUR, wenn jedes Element des Arrays ein Array ist. Wenn das Array gemischte Typen wie Skalare enthält, tritt ein Fehler auf.
Otheus
@Otheus Das liegt daran, dass die obige Lösung keine Rekursion verwendet. Wie Sie sagten, erfordert es ein Array von Array. Auf der positiven Seite sollte dies jedoch viel schneller sein als bei den anderen Methoden, da es keinen zusätzlichen Overhead für die Funktionsaufrufe gibt.
Joyce Babu
2
Wird einen Fehler auslösen, wenn das äußere Array leer ist, könnte vermeidbar sein, wenn es mit einem leeren Array kombiniert wirdarray_merge([], ...$a);
Mohamed Gharib
@ MohamedGharib Schöner Fang.
Joyce Babu
Wenn Sie assoziative Arrays verwenden, können Sie diese Lösung überprüfen. Stackoverflow.com/questions/40663687/…
alex
24

Um die Rekursion zu reduzieren (wie Sie es gewünscht haben), können Sie einen Stapel verwenden . Natürlich können Sie dies in eine eigene Funktion umsetzen array_flatten. Das Folgende ist eine Version, die ohne Schlüssel funktioniert:

function array_flatten(array $array)
{
    $flat = array(); // initialize return array
    $stack = array_values($array); // initialize stack
    while($stack) // process stack until done
    {
        $value = array_shift($stack);
        if (is_array($value)) // a value to further process
        {
            $stack = array_merge(array_values($value), $stack);
        }
        else // a value to take
        {
           $flat[] = $value;
        }
    }
    return $flat;
}

Elemente werden in ihrer Reihenfolge verarbeitet. Da Unterelemente auf den Stapel verschoben werden, werden sie als Nächstes verarbeitet.

Es ist auch möglich, Schlüssel zu berücksichtigen. Sie benötigen jedoch eine andere Strategie, um den Stapel zu handhaben. Dies ist erforderlich, da Sie sich mit möglichen doppelten Schlüsseln in den Unterarrays befassen müssen. Eine ähnliche Antwort in einer verwandten Frage: PHP Gehen Sie durch mehrdimensionale Arrays, während Sie die Schlüssel beibehalten

Ich bin mir nicht ganz sicher, aber ich hatte dies in der Vergangenheit getestet: Das RecurisiveIteratorverwendet Rekursion, es hängt also davon ab, was Sie wirklich brauchen. Sollte es möglich sein, einen rekursiven Iterator auch basierend auf Stapeln zu erstellen:

foreach(new FlatRecursiveArrayIterator($array) as $key => $value)
{
    echo "** ($key) $value\n";
}

Demo

Ich habe es bisher nicht geschafft, den Stack zu implementieren, auf dessen Basis RecursiveIteratorich das für eine gute Idee halte.

hakre
quelle
+1 für herausragende Funktion array_flatten. Ich musste if(!empty($value)){$flat[] = $value}innerhalb der else-Anweisung hinzufügen , um zu verhindern, dass dem Ergebnisarray Leerzeichen hinzugefügt werden. Tolle Funktion!
Alex Sarnowski
19

Einfache und einzeilige Antwort.

function flatten_array(array $array)
{
    return iterator_to_array(
         new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array)));
}

Verwendung:

$array = [
    'name' => 'Allen Linatoc',
    'profile' => [
        'age' => 21,
        'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
    ]
];

print_r( flatten_array($array) );

Ausgabe (in PsySH):

Array
(
    [name] => Allen Linatoc
    [age] => 21
    [0] => Call of Duty
    [1] => Titanfall
    [2] => Far Cry
)

Jetzt liegt es ganz bei Ihnen, wie Sie mit den Schlüsseln umgehen. Prost


BEARBEITEN (2017-03-01)

Zitat von Nigel Aldertons Anliegen / Problem:

Zur Verdeutlichung bleiben dabei Schlüssel (auch numerische) erhalten, sodass Werte mit demselben Schlüssel verloren gehen. Zum Beispiel $array = ['a',['b','c']]wird Array ([0] => b, [1] => c ). Das 'a'geht verloren, weil es 'b'auch einen Schlüssel von hat0

Zitat von Svishs Antwort:

Nur falsch als zweite Parameter hinzufügen ($use_keys)an den iterator_to_array Aufruf

Allen Linatoc
quelle
Zur Verdeutlichung bleiben dabei Schlüssel (auch numerische) erhalten, sodass Werte mit demselben Schlüssel verloren gehen. Zum Beispiel $array = ['a',['b','c']]wird Array ([0] => b, [1] => c ). Das 'a'geht verloren, weil es 'b'auch einen Schlüssel von hat 0.
Nigel Alderton
1
@NigelAlderton Fügen Sie dem Aufruf einfach falseals zweiten Parameter ( $use_keys) hinzu iterator_to_array.
Svish
18

Verwendet Rekursion. Wenn Sie sehen, wie unkomplex es ist, wird sich Ihre Angst vor Rekursion hoffentlich auflösen, sobald Sie sehen, wie unkomplex es ist.

function flatten($array) {
    if (!is_array($array)) {
        // nothing to do if it's not an array
        return array($array);
    }

    $result = array();
    foreach ($array as $value) {
        // explode the sub-array, and add the parts
        $result = array_merge($result, flatten($value));
    }

    return $result;
}


$arr = array('foo', array('nobody', 'expects', array('another', 'level'), 'the', 'Spanish', 'Inquisition'), 'bar');
echo '<ul>';
foreach (flatten($arr) as $value) {
    echo '<li>', $value, '</li>';
}
echo '<ul>';

Ausgabe:

<ul><li>foo</li><li>nobody</li><li>expects</li><li>another</li><li>level</li><li>the</li><li>Spanish</li><li>Inquisition</li><li>bar</li><ul>
Nilamo
quelle
1
Ich habe keine Angst vor Rekursion, ich möchte nur andere Wege lernen, um dasselbe zu tun.
Alix Axel
13
+1 für diese Rekursion: Wenn Sie sehen, wie unkomplex sie ist, wird sich Ihre Angst vor der Rekursion hoffentlich auflösen, sobald Sie sehen, wie unkomplex sie ist.
Tiberiu-Ionuț Stan
1
OK, das ist über mich. Wie es möglich ist, ist diese Antwort ("Ich fürchte keine Rekursion") dreieinhalb Jahre älter (24. August 2009) als die ursprüngliche Aussage ("(...) Ihre Angst vor einer Rekursion wird sich auflösen (... ) "), gemacht am 5. Februar 13?
Trejder
18

Ich dachte nur, ich würde darauf hinweisen, dass dies eine Falte ist, damit array_reduce verwendet werden kann:

array_reduce($my_array, 'array_merge', array());

BEARBEITEN: Beachten Sie, dass dies so zusammengesetzt werden kann, dass eine beliebige Anzahl von Ebenen abgeflacht wird. Wir können dies auf verschiedene Arten tun:

// Reduces one level
$concat   = function($x) { return array_reduce($x, 'array_merge', array()); };

// We can compose $concat with itself $n times, then apply it to $x
// This can overflow the stack for large $n
$compose  = function($f, $g) {
    return function($x) use ($f, $g) { return $f($g($x)); };
};
$identity = function($x) { return $x; };
$flattenA = function($n) use ($compose, $identity, $concat) {
    return  function($x) use ($compose, $identity, $concat, $n) {
        return ($n === 0)? $x
                         : call_user_func(array_reduce(array_fill(0, $n, $concat),
                                                       $compose,
                                                       $identity),
                                          $x);
    };
};

// We can iteratively apply $concat to $x, $n times
$uncurriedFlip     = function($f) {
    return  function($a, $b) use ($f) {
        return $f($b, $a);
    };
};
$iterate  = function($f) use ($uncurriedFlip) {
    return  function($n) use ($uncurriedFlip, $f) {
    return  function($x) use ($uncurriedFlip, $f, $n) {
        return ($n === 0)? $x
                         : array_reduce(array_fill(0, $n, $f),
                                        $uncurriedFlip('call_user_func'),
                                        $x);
    }; };
};
$flattenB = $iterate($concat);

// Example usage:
$apply    = function($f, $x) {
    return $f($x);
};
$curriedFlip = function($f) {
    return  function($a) use ($f) {
    return  function($b) use ($f, $a) {
        return $f($b, $a);
    }; };
};

var_dump(
    array_map(
        call_user_func($curriedFlip($apply),
                       array(array(array('A', 'B', 'C'),
                                   array('D')),
                             array(array(),
                                   array('E')))),
        array($flattenA(2), $flattenB(2))));

Natürlich könnten wir auch Schleifen verwenden, aber die Frage fragt nach einer Kombinatorfunktion nach dem Vorbild von array_map oder array_values.

Warbo
quelle
Mehrdimensional! = Zweidimensional.
Alix Axel
@atamur Dies funktioniert unter PHP 5.3+. Wie im Änderungsprotokoll für array_reduce angegeben, konnte $ initial nur eine Ganzzahl vor 5.3 sein, dann durfte es "gemischt" werden (dh alles, was Ihre Reduktionsfunktion unterstützt)
Warbo
1
@AlixAxel Sie haben Recht, dass mehrdimensional! = Zweidimensional, aber dies kann so zusammengesetzt werden, dass eine beliebige Anzahl von Ebenen abgeflacht wird. Eine schöne Konsequenz beim Zusammenstellen von Falten ist, dass eine feste Grenze eingehalten wird. Wenn ich ein Array habe, das in 5 Ebenen verschachtelt ist, kann ich foldes in 4 Ebenen oder fold . foldin 3 Ebenen oder fold . fold . foldin 2 Ebenen usw. unterteilen. Dadurch wird auch verhindert, dass Fehler versteckt werden. z.B. Wenn ich ein 5D-Array reduzieren möchte, aber ein 4D-Array erhalten möchte, wird der Fehler sofort ausgelöst.
Warbo
Ich liebe diese Lösung für zweidimensionale Arrays. Passt perfekt zur Rechnung.
Tom Auger
Ich bin damit einverstanden, dass Ihre einstufige Definition die beste Antwort ist, sie ist auch wunderbar ordentlich. Wie auch immer ich denke, Sie haben es falsch benannt $concat, ich denke, Sie sollten es einfach nennen $flatten. array_mergeist das PHP-Äquivalent von concat. Ich habe versucht , array_concatals Alias ​​für hinzugefügt zu werden array_merge.
icc97
9

Flacht nur zweidimensionale Arrays ab:

$arr = [1, 2, [3, 4]];
$arr = array_reduce($arr, function ($a, $b) {
     return array_merge($a, (array) $b);
}, []);

// Result: [1, 2, 3, 4]
artnikpro
quelle
5

Diese Lösung ist nicht rekursiv. Beachten Sie, dass die Reihenfolge der Elemente etwas gemischt ist.

function flatten($array) {
    $return = array();
    while(count($array)) {
        $value = array_shift($array);
        if(is_array($value))
            foreach($value as $sub)
                $array[] = $sub;
        else
            $return[] = $value;
    }
    return $return;
}
zu viel php
quelle
1
Kluge Idee, aber es gibt einen Fehler. "$ array [] = $ value" fügt nicht alle Elemente von $ value zu $ ​​array hinzu, sondern lediglich $ value selbst. Wenn Sie diesen Code ausführen, wird er auf unbestimmte Zeit wiederholt.
Todd Owen
Ja, shiftingder Wert aus dem Array und das erneute Anhängen an das Ende macht wenig Sinn. Ich denke du wolltest array_merge()stattdessen?
Täuschung
4

Ich glaube, dies ist die sauberste Lösung, ohne Mutationen oder unbekannte Klassen zu verwenden.

<?php

function flatten($array)
{
    return array_reduce($array, function($acc, $item){
        return array_merge($acc, is_array($item) ? flatten($item) : [$item]);
    }, []);
}


// usage
$array = [1, 2, [3, 4], [5, [6, 7]], 8, 9, 10];
print_r(flatten($array));
Dariush Alipour
quelle
3

Probieren Sie die folgende einfache Funktion aus:

function _flatten_array($arr) {
  while ($arr) {
    list($key, $value) = each($arr); 
    is_array($value) ? $arr = $value : $out[$key] = $value;
    unset($arr[$key]);
  }
  return (array)$out;
}

Also daraus:

array (
  'und' => 
  array (
    'profiles' => 
    array (
      0 => 
      array (
        'commerce_customer_address' => 
        array (
          'und' => 
          array (
            0 => 
            array (
              'first_name' => 'First name',
              'last_name' => 'Last name',
              'thoroughfare' => 'Address 1',
              'premise' => 'Address 2',
              'locality' => 'Town/City',
              'administrative_area' => 'County',
              'postal_code' => 'Postcode',
            ),
          ),
        ),
      ),
    ),
  ),
)

du erhältst:

array (
  'first_name' => 'First name',
  'last_name' => 'Last name',
  'thoroughfare' => 'Address 1',
  'premise' => 'Address 2',
  'locality' => 'Town/City',
  'administrative_area' => 'County',
  'postal_code' => 'Postcode',
)
Kenorb
quelle
Vielleicht sollten Sie Ihre Funktion überprüfen ... scheint keine Arbeit wie erwartet
Emiliano
@Emiliano Versuchen Sie, eine neue Frage zu stellen. Möglicherweise sind Ihre Eingabedaten anders, sodass dies in Ihrem speziellen Fall nicht funktioniert.
Kenorb
Wir haben nur wenige Probleme. Jedes ist eine veraltete Funktion. Sie können den Punkt verbessern, an dem Sie hier kein neuer Typ waren. Sie sollten es als zweites wissen, wenn Ihr Code mit einer bestimmten Version von PHP funktioniert. Sagen Sie es als drittes, wenn Sie nicht mit allen Daten arbeiten. Sagen Sie es
Emiliano
2

Der Trick besteht darin, sowohl das Quell- als auch das Zielarray als Referenz zu übergeben.

function flatten_array(&$arr, &$dst) {
    if(!isset($dst) || !is_array($dst)) {
        $dst = array();
    }
    if(!is_array($arr)) {
        $dst[] = $arr;
    } else {
        foreach($arr as &$subject) {
            flatten_array($subject, $dst);
        }
    }
}

$recursive = array('1', array('2','3',array('4',array('5','6')),'7',array(array(array('8'),'9'),'10')));
echo "Recursive: \r\n";
print_r($recursive);
$flat = null;
flatten_array($recursive, $flat);

echo "Flat: \r\n";
print_r($flat);

// If you change line 3 to $dst[] = &$arr; , you won't waste memory,
// since all you're doing is copying references, and imploding the array 
// into a string will be both memory efficient and fast:)

echo "String:\r\n";
echo implode(',',$flat);
Rick Garcia
quelle
2
/**
 * For merging values of a multidimensional array into one 
 *
 * $array = [
 *     0 => [
 *         0 => 'a1',
 *         1 => 'b1',
 *         2 => 'c1',
 *         3 => 'd1'
 *     ],
 *     1 => [
 *         0 => 'a2',
 *         1 => 'b2',
 *         2 => 'c2',
 *     ]
 * ];
 *
 * becomes : 
 *
 * $array = [
 *     0 => 'a1',
 *     1 => 'b1',
 *     2 => 'c1',
 *     3 => 'd1',
 *     4 => 'a2',
 *     5 => 'b2',
 *     6 => 'c2',
 *     
 * ]
 */
array_reduce
(
    $multiArray
    , function ($lastItem, $currentItem) {
        $lastItem = $lastItem ?: array();
        return array_merge($lastItem, array_values($currentItem));
    }
);

Kernausschnitt

Arsham
quelle
Dies scheint nur zweidimensionale Arrays zu unterstützen.
Alix Axel
Du hast recht. Es macht keinen Sinn, es zu benutzen. Ich denke, die beste Lösung ist die Antwort von "too much php".
Arsham
2

Sie können es mit Ouzo Goodies tun :

 $result = Arrays::flatten($multidimensional);

Siehe: Hier

woru
quelle
2

Wenn Sie eine Rekursion wirklich nicht mögen ... versuchen Sie stattdessen zu verschieben :)

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
$o = [];
for ($i=0; $i<count($a); $i++) {
    if (is_array($a[$i])) {
        array_splice($a, $i+1, 0, $a[$i]);
    } else {
        $o[] = $a[$i];
    }
}

Hinweis: In dieser einfachen Version werden Array-Schlüssel nicht unterstützt.

BurninLeo
quelle
Dies ist ein interessanter Ansatz. Im Gegensatz zu den anderen Lösungen wird das ursprüngliche Array ($ a) bearbeitet. Wenn Sie es durch ein ersetzen, ist es continueetwas schneller.
Pcarvalho
2

Wie wäre es mit einem rekursiven Generator? https://ideone.com/d0TXCg

<?php

$array = [
    'name' => 'Allen Linatoc',
    'profile' => [
        'age' => 21,
        'favourite_games' => [ 'Call of Duty', 'Titanfall', 'Far Cry' ]
    ]
];

foreach (iterate($array) as $item) {
    var_dump($item);
};

function iterate($array)
{
    foreach ($array as $item) {
        if (is_array($item)) {
            yield from iterate($item);
        } else {
            yield $item;
        }
    }
}
Andriy
quelle
1

Für PHP 5.2

function flatten(array $array) {
    $result = array();

    if (is_array($array)) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                $result = array_merge($result, flatten($v));
            } else {
                $result[] = $v;
            }
        }
    }

    return $result;
}
Alexei T.
quelle
Bitte fügen Sie dieser Nur-Code-Antwort eine Erklärung bei.
Mickmackusa
1

Diese Version kann tiefe, flache oder eine bestimmte Anzahl von Ebenen ausführen:

/**
 * @param  array|object $array  array of mixed values to flatten
 * @param  int|boolean  $level  0:deep, 1:shallow, 2:2 levels, 3...
 * @return array
 */
function flatten($array, $level = 0) {
    $level = (int) $level;
    $result = array();
    foreach ($array as $i => $v) {
        if (0 <= $level && is_array($v)) {
            $v = flatten($v, $level > 1 ? $level - 1 : 0 - $level);
            $result = array_merge($result, $v);
        } elseif (is_int($i)) {
            $result[] = $v;
        } else {
            $result[$i] = $v; 
        }
    }
    return $result;
}
Ryanve
quelle
Erklären Sie zukünftigen Forschern nicht nur , was dieses Snippet leisten kann , sondern auch, wie es funktioniert.
Mickmackusa
1

Weil der Code hier beängstigend aussieht. Hier ist eine Funktion, die auch ein mehrdimensionales Array in eine HTML-Form-kompatible Syntax konvertiert, die jedoch einfacher zu lesen ist.

/**
 * Flattens a multi demensional array into a one dimensional
 * to be compatible with hidden html fields.
 *
 * @param array $array
 *  Array in the form:
 *  array(
 *    'a' => array(
 *      'b' => '1'
 *    )
 *  )
 *
 * @return array
 *  Array in the form:
 *  array(
 *    'a[b]' => 1,
 *  )
 */
function flatten_array($array) {
  // Continue until $array is a one-dimensional array.
  $continue = TRUE;
  while ($continue) {
    $continue = FALSE;

    // Walk through top and second level of $array and move 
    // all values in the second level up one level.
    foreach ($array as $key => $value) {
      if (is_array($value)) {
        // Second level found, therefore continue.
        $continue = TRUE;

        // Move each value a level up.
        foreach ($value as $child_key => $child_value) {
          $array[$key . '[' . $child_key . ']'] = $child_value;
        }

        // Remove second level array from top level.
        unset($array[$key]);
      }
    }
  }

  return $array;
}
Gellweiler
quelle
1

Dies kann durch Verwendung erreicht werden array_walk_recursive

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
array_walk_recursive($a, function($v) use (&$r){$r[]=$v;});
print_r($r);

Arbeitsbeispiel: - https://3v4l.org/FpIrG

Rakesh Jakhar
quelle
0

Dies ist meine Lösung unter Verwendung einer Referenz:

function arrayFlatten($array_in, &$array_out){

    if(is_array($array_in)){
        foreach ($array_in as $element){
               arrayFlatten($element, $array_out);
        }
    }
    else{
        $array_out[] = $array_in; 
    }
}

$arr1 = array('1', '2', array(array(array('3'), '4', '5')), array(array('6')));

arrayFlatten($arr1, $arr2);

echo "<pre>";
print_r($arr2);
echo "</pre>";
Martyn Shutt
quelle
Bitte geben Sie eine Erklärung an, wie Ihr Snippet funktioniert und warum es eine gute Idee ist. Nur-Code-Antworten sind bei StackOverflow von geringem Wert, da sie das OP und zukünftige Forscher schlecht ausbilden / befähigen. Denken Sie daran, wir sprechen niemals NUR mit dem OP. Alte Seiten werden zum Schließen neuer Seiten verwendet. Daher müssen Seiten informativ genug sein, um Probleme auch für zukünftige Fragesteller zu lösen.
Mickmackusa
0
<?php
//recursive solution

//test array
$nested_array = [[1,2,[3]],4,[5],[[[6,[7=>[7,8,9,10]]]]]];

/*-----------------------------------------
function call and return result to an array
------------------------------------------*/
$index_count = 1;
$flatered_array = array();
$flatered_array = flat_array($nested_array, $index_count);

/*-----------------------------------------
Print Result
-----------------------------------------*/
echo "<pre>";
print_r($flatered_array);


/*-----------------------------------------
function to flaten an array 
-----------------------------------------*/
function flat_array($nested_array, & $index_count, & $flatered_array) {

  foreach($nested_array AS $key=>$val) {
      if(is_array($val)) {
        flat_array($val, $index_count, $flatered_array);
      }
      else {
        $flatered_array[$index_count] = $val;
        ++$index_count;
      }      
  }

return $flatered_array;
}
?>
Furqan befreit
quelle
0

Hier ist ein vereinfachter Ansatz:

$My_Array = array(1,2,array(3,4, array(5,6,7), 8), 9);

function checkArray($value) {
    foreach ($value as $var) {
        if ( is_array($var) ) {
            checkArray($var);
        } else {
            echo $var;
        }
    }
}

checkArray($My_Array);
Jack
quelle
0

Jeder, der nach einer wirklich sauberen Lösung sucht; Hier ist eine Option:

$test_array = array(
    array('test' => 0, 0, 0, 0),
    array(0, 0, 'merp' => array('herp' => 'derp'), 0),
    array(0, 0, 0, 0),
    array(0, 0, 0, 0)
);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($test_array));
var_dump( iterator_to_array($it, false) ) ; 

Druckt

 0 0 0 0 0 0 derp 0 0 0 0 0 0 0 0 0
Lewis
quelle
0

Einfach eine andere Lösung posten)

function flatMultidimensionalArray(array &$_arr): array
{
    $result = [];
    \array_walk_recursive($_arr, static function (&$value, &$key) use (&$result) {
        $result[$key] = $value;
    });

    return $result;
}
James Bond
quelle
0

Wenn Sie auch Ihre Schlüssel behalten möchten, ist das eine Lösung.

function reduce(array $array) {
    $return = array();
    array_walk_recursive($array, function($value, $key) use (&$return) { $return[$key] = $value; });
    return $return;
}

Leider werden nur endgültig verschachtelte Arrays ohne mittlere Schlüssel ausgegeben. Also für das folgende Beispiel:

$array = array(
    'sweet' => array(
        'a' => 'apple',
        'b' => 'banana'),
    'sour' => 'lemon'); 
print_r(flatten($fruits));

Ausgabe ist:

Array
(
    [a] => apple
    [b] => banana
    [sour] => lemon
)
Tajni
quelle
-1

Ich musste ein mehrdimensionales PHP-Array im HTML-Eingabeformat darstellen.

$test = [
    'a' => [
        'b' => [
            'c' => ['a', 'b']
        ]
    ],
    'b' => 'c',
    'c' => [
        'd' => 'e'
    ]
];

$flatten = function ($input, $parent = []) use (&$flatten) {
    $return = [];

    foreach ($input as $k => $v) {
        if (is_array($v)) {
            $return = array_merge($return, $flatten($v, array_merge($parent, [$k])));
        } else {
            if ($parent) {
                $key = implode('][', $parent) . '][' . $k . ']';

                if (substr_count($key, ']') != substr_count($key, '[')) {
                    $key = preg_replace('/\]/', '', $key, 1);
                }
            } else {
                $key = $k;
            }           

            $return[$key] = $v;
        }
    }

    return $return;
};

die(var_dump( $flatten($test) ));

array(4) {
  ["a[b][c][0]"]=>
  string(1) "a"
  ["a[b][c][1]"]=>
  string(1) "b"
  ["b"]=>
  string(1) "c"
  ["c[d]"]=>
  string(1) "e"
}
Gajus
quelle
@AlixAxel Wie ist dieser Kommentar relativ? Falscher Beitrag ..?
Gajus
Nein. Ich dachte, es wäre ziemlich ähnlich zu dem, was Sie tun, und habe beschlossen, es zu teilen. Ich denke, der einzige Unterschied besteht darin, dass meine Darstellung auch gültiges PHP ist - der Form $var['a']['b']['c'][0] = 'a'; ....
Alix Axel
Ich brauchte absichtlich HTML-Ausgabe. Trotzdem danke fürs Teilen.
Gajus
1
Ich denke, dass dies die richtige Antwort auf die falsche Frage ist. Versuchen Sie bei der Beantwortung bitte, die gestellte Frage so zu beantworten, wie sie gestellt wird. Andernfalls können die Seiten vom Kernthema abweichen und zukünftige Forscher verwirren.
Mickmackusa
-1

Wenn Sie ein Array von Objekten haben und es mit einem Knoten reduzieren möchten, verwenden Sie einfach diese Funktion:

function objectArray_flatten($array,$childField) {
    $result = array();
    foreach ($array as $node)
    {
        $result[] = $node;
        if(isset($node->$childField))
        {
            $result = array_merge(
                $result, 
                objectArray_flatten($node->$childField,$childField)
            );
            unset($node->$childField);
        }

    }
    return $result;
}
حسین شکرزاده
quelle