Wie kann man ein mehrdimensionales Array in PHP auf ein einfaches Array "reduzieren"?

82

Es ist wahrscheinlich eine Anfängerfrage, aber ich gehe die Dokumentation schon länger durch und kann keine Lösung finden. Ich dachte, ich könnte implode für jede Dimension verwenden und diese Zeichenfolgen dann wieder zusammenfügen str_split, um ein neues einfaches Array zu erstellen. Ich weiß jedoch nie, ob das Verknüpfungsmuster nicht auch in Werten enthalten ist, und daher können str_splitmeine ursprünglichen Werte nach dem Ausführen beschädigt werden.

Gibt es so etwas wie combine($array1, $array2)Arrays innerhalb eines mehrdimensionalen Arrays?

Adriana
quelle
Bitte überprüfen Sie diesen Link für die Lösung : stackoverflow.com/questions/14951811/…
Prasanth Bendra
1
Eine weitere gute Referenzfrage mit vielleicht besseren Antworten: Wie wird ein mehrdimensionales Array abgeflacht?
hakre

Antworten:

42

Verwenden array_walk_recursive

<?php

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

$objTmp = (object) array('aFlat' => array());

array_walk_recursive($aNonFlat, create_function('&$v, $k, &$t', '$t->aFlat[] = $v;'), $objTmp);

var_dump($objTmp->aFlat);

/*
array(11) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
  [5]=>
  int(6)
  [6]=>
  int(7)
  [7]=>
  int(8)
  [8]=>
  int(9)
  [9]=>
  int(10)
  [10]=>
  int(11)
}
*/

?>

Getestet mit PHP 5.5.9-1ubuntu4.24 (cli) (erstellt: 16. März 2018 12:32:06)

Luc M.
quelle
Weiß jemand, warum dies nicht funktioniert, es sei denn, ich verwende die (abgeschriebene) Anrufzeit als Referenz. dh array_walk_recursive ($ array, create_function ('& $ v, $ k, & $ t', '$ t [] = $ v;'), & $ abgeflacht); Die Funktionsdefinition ist korrekt als Referenzübergabe definiert. funktioniert aber nur, wenn ich während der Anrufzeit als Referenz vorbeigehe.
Jskulski
2
@jskilski Objekte ( $objTmpin diesem Beispiel) werden automatisch als Referenz übergeben. Arrays sind nicht. Versuchen Sie stattdessen eine anonyme Funktion ( php.net/manual/en/functions.anonymous.php ) zu verwenden create_function.
Dave1010
1
Dies funktioniert nicht in PHP 5.3.3 aufgrund eines Fehlers in array_walk_recursive - bugs.php.net/bug.php?id=52719
crazyphoton
1
@crazyphoton Der Knick sagt auchThis bug has been fixed in SVN.
Luc M
10
Warum erwähnt diese Antwort die Verwendung array_values()? Ich kann überhaupt keine Verwendung dieser Funktion in der Antwort sehen.
Thomasrutter
131
$array  = your array

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

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

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

Hier ist eine andere Lösung (funktioniert mit mehrdimensionalem Array):

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);
Prasanth Bendra
quelle
Diese Antwort ist viel schneller als die akzeptierte Antwort.
Roham Rafii
8
Seit php5.3 können Sie jetzt den Splat-Operator verwenden: $result = array_merge(...$array); php.net/manual/en/…
Redzarf
Ihre erste Antwort funktioniert nicht mit einem mehrdimensionalen Array. 3v4l.org/tY8vD
Dearsina
53

Dies ist eine einzeilige, SUPER einfach zu bedienende:

$result = array();
array_walk_recursive($original_array,function($v) use (&$result){ $result[] = $v; });

Es ist sehr leicht zu verstehen, innerhalb der anonymen Funktion / Schließung. $vist der Wert Ihres $original_array.

Arnold Roa
quelle
4
Dies ist die einzige, die für mich in einem zweistufigen Array funktioniert hat.
Ciprian Tepes
18
// $array = your multidimensional array

$flat_array = array();

foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $k=>$v){

$flat_array[$k] = $v;

}

Ebenfalls dokumentiert: http://www.phpro.org/examples/Flatten-Array.html

upallnite
quelle
2
Hinweis: Nur für Arrays von Grundelementen verwenden. "RecursiveArrayIterator behandelt alle Objekte als Kinder und versucht, in sie zurückzukehren." php.net/manual/en/class.recursivearrayiterator.php#106519
ReactiveRaven
@hakre: +1 stimmte zu: Das Hinzufügen iterator_to_array()zu dieser Antwort würde die Notwendigkeit der foreachSchleife zunichte machen . Es könnte eine einfache Einzeilerfunktion sein. (wenn auch eine etwas lange einzeilige)
DEZA
2
Ich weiß, dass dies alt, aber immer noch nützlich ist, aber das $ k muss durch etwas Einzigartiges wie einen Zähler ersetzt werden. Wenn Sie nur $ k verwenden, werden Elemente entfernt, wenn die Namen in den inneren Arrays mit denen des Hauptarrays identisch sind.
Austin Best
12

Wenn Sie speziell über ein Array von Arrays verfügen, das nicht weiter als eine Ebene tief ist (ein Anwendungsfall, den ich häufig finde), können Sie mit array_mergedem Splat-Operator davonkommen.

<?php

$notFlat = [[1,2],[3,4]];
$flat = array_merge(...$notFlat);
var_dump($flat);

Ausgabe:

array(4) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
}

Der Splat-Operator ändert das Array von Arrays effektiv in eine Liste von Arrays als Argumente für array_merge.

Josh Johnson
quelle
Das scheint mir die beste Antwort zu sein. Es funktioniert nicht mit String-Schlüsseln, kann aber leicht geändert werden, um dies zu tun:$flat = array_merge( array_keys( $notFlat ), ...array_values( $notFlat ) );
Ian Dunn
6

Mit PHP 7 können Sie Generatoren und Generator Delegation ( yield from) verwenden, um ein Array zu reduzieren:

function array_flatten_iterator (array $array) {
    foreach ($array as $value) {
        if (is_array($value)) {
            yield from array_flatten_iterator($value);
        } else {
            yield $value;
        }
    }
}

function array_flatten (array $array) {
    return iterator_to_array(array_flatten_iterator($array), false);
}

Beispiel:

$array = [
    1,
    2,
    [
        3,
        4,
        5,
        [
            6,
            7
        ],
        8,
        9,
    ],
    10,
    11,
];    

var_dump(array_flatten($array));

http://3v4l.org/RU30W

Kelunik
quelle
5
function flatten_array($array, $preserve_keys = 0, &$out = array()) {
    # Flatten a multidimensional array to one dimension, optionally preserving keys.
    #
    # $array - the array to flatten
    # $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
    # $out - internal use argument for recursion
    foreach($array as $key => $child)
        if(is_array($child))
            $out = flatten_array($child, $preserve_keys, $out);
        elseif($preserve_keys + is_string($key) > 1)
            $out[$key] = $child;
        else
            $out[] = $child;
    return $out;
}
Chaos
quelle
Entschuldigung, aber es scheint nicht richtig mit mehrdimensionalen Arrays
Álvaro González
5

Eine andere Methode aus den Benutzerkommentaren von PHP (vereinfacht) und hier :

function array_flatten_recursive($array) { 
   if (!$array) return false;
   $flat = array();
   $RII = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
   foreach ($RII as $value) $flat[] = $value;
   return $flat;
}

Der große Vorteil dieser Methode besteht darin, dass sie die Tiefe der Rekursion verfolgt, falls Sie diese beim Abflachen benötigen.
Dies wird Folgendes ausgeben:

$array = array( 
    'A' => array('B' => array( 1, 2, 3)), 
    'C' => array(4, 5) 
); 
print_r(array_flatten_recursive($array)); 

#Returns: 
Array ( 
    [0] => 1 
    [1] => 2 
    [2] => 3 
    [3] => 4 
    [4] => 5 
)
SamGoody
quelle
3
Hinweis: Nur für Arrays von Grundelementen verwenden. "RecursiveArrayIterator behandelt alle Objekte als Kinder und versucht, in sie zurückzukehren." php.net/manual/en/class.recursivearrayiterator.php#106519
ReactiveRaven
4

Eine nicht rekursive Lösung (aber auftragszerstörend):

function flatten($ar) {
    $toflat = array($ar);
    $res = array();

    while (($r = array_shift($toflat)) !== NULL) {
        foreach ($r as $v) {
            if (is_array($v)) {
                $toflat[] = $v;
            } else {
                $res[] = $v;
            }
        }
    }

    return $res;
}
Phihag
quelle
4

In PHP> = 5.3 und basierend auf Luc Ms Antwort (der ersten) können Sie solche Verschlüsse verwenden

array_walk_recursive($aNonFlat, function(&$v, $k, &$t){$t->aFlat[] = $v;}, $objTmp);

Ich liebe das, weil ich den Code der Funktion nicht mit Anführungszeichen umgeben muss, wie bei Verwendung von create_function ()

hisa_py
quelle
1
wenn Sie anonyme Funktionen verwenden, können Sie auch ein aufgenommenes Verschluss Variable direkt anstatt dieses objTempZeug
user102008
1
Es gibt einen Fehler in PHP5.3.3, der zum Absturz führt - bugs.php.net/bug.php?id=52719
crazyphoton
2

Verwenden von Funktionen höherer Ordnung (Hinweis: Ich verwende anonyme Inline-Funktionen , die in PHP 5.3 enthalten sind):

function array_flatten($array) {
    return array_reduce(
        $array,
        function($prev, $element) {
            if (!is_array($element))
                $prev[] = $element;
            else
                $prev = array_merge($prev, array_flatten($element));
            return $prev;
        },
        array()
    );
}
Paul d'Aoust
quelle
1

Ein neuer Ansatz, der auf der vorherigen Beispielfunktion basiert, die vom Chaos eingereicht wurde und den Fehler beim Überschreiben von Zeichenfolgenschlüsseln in Multiarrays behebt:

# Flatten a multidimensional array to one dimension, optionally preserving keys.
# $array - the array to flatten
# $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
# $out - internal use argument for recursion

function flatten_array($array, $preserve_keys = 2, &$out = array(), &$last_subarray_found) 
{
        foreach($array as $key => $child)
        {
            if(is_array($child))
            {
                $last_subarray_found = $key;
                $out = flatten_array($child, $preserve_keys, $out, $last_subarray_found);
            }
            elseif($preserve_keys + is_string($key) > 1)
            {
                if ($last_subarray_found)
                {
                    $sfinal_key_value = $last_subarray_found . "_" . $key;
                }
                else
                {
                    $sfinal_key_value = $key;
                }
                $out[$sfinal_key_value] = $child;
            }
            else
            {
                $out[] = $child;
            }
        }

        return $out;
}

Example:
$newarraytest = array();
$last_subarray_found = "";
$this->flatten_array($array, 2, $newarraytest, $last_subarray_found);
xtrm
quelle
1
/*consider $mArray as multidimensional array and $sArray as single dimensional array
this code will ignore the parent array
*/

function flatten_array2($mArray) {
    $sArray = array();

    foreach ($mArray as $row) {
        if ( !(is_array($row)) ) {
            if($sArray[] = $row){
            }
        } else {
            $sArray = array_merge($sArray,flatten_array2($row));
        }
    }
    return $sArray;
}
Iman
quelle
1

Sie können dies versuchen:

function flat_an_array($a)
{
    foreach($a as $i)
    {
        if(is_array($i)) 
        {
            if($na) $na = array_merge($na,flat_an_array($i));
            else $na = flat_an_array($i);
        }
        else $na[] = $i;
    }
    return $na;
}
Tom Sawyer
quelle
1

Wenn Sie mit dem Verlust von Array-Schlüsseln einverstanden sind, können Sie ein mehrdimensionales Array mithilfe eines rekursiven Abschlusses als Rückruf reduzieren, der array_values ​​() verwendet. Stellen Sie dabei sicher, dass dieser Rückruf ein Parameter für array_walk () ist.

<?php  

$array = [1,2,3,[5,6,7]];
$nu_array = null;
$callback = function ( $item ) use(&$callback, &$nu_array) {
    if (!is_array($item)) {
    $nu_array[] = $item;
    }
    else
    if ( is_array( $item ) ) {
     foreach( array_values($item) as $v) {
         if ( !(is_array($v))) {
             $nu_array[] = $v;
         }
         else
         { 
             $callback( $v );
         continue;
         }    
     }
    }
};

array_walk($array, $callback);
print_r($nu_array);

Der einzige Nachteil des vorhergehenden Beispiels besteht darin, dass weitaus mehr Code geschrieben wird als bei der folgenden Lösung, bei der array_walk_recursive () zusammen mit einem vereinfachten Rückruf verwendet wird:

<?php  

$array = [1,2,3,[5,6,7]];

$nu_array = [];
array_walk_recursive($array, function ( $item ) use(&$nu_array )
                     {
                         $nu_array[] = $item;
                     }
);
print_r($nu_array);

Siehe Live-Code

Dieses Beispiel scheint dem vorherigen vorzuziehen, da es die Details darüber verbirgt, wie Werte aus einem mehrdimensionalen Array extrahiert werden. Sicherlich tritt eine Iteration auf, aber ob es sich um eine Rekursion oder um Kontrollstrukturen handelt, wissen Sie nur aus der Durchsicht von array.c . Da sich die funktionale Programmierung eher auf Input und Output als auf die Minutien konzentriert, um ein Ergebnis zu erzielen, kann man sich sicherlich keine Gedanken darüber machen, wie die Iteration hinter den Kulissen erfolgt, bis ein perspektivischer Arbeitgeber eine solche Frage stellt.

slevy1
quelle
1

Ich habe einen einfachen Weg gefunden, um ein mehrstufiges Array in ein Array umzuwandeln. Ich benutze die Funktion "http_build_query", die das Array in eine URL-Zeichenfolge konvertiert. Teilen Sie dann die Zeichenfolge mit explode und dekodieren Sie den Wert.

Hier ist ein Beispiel.

$converted = http_build_query($data);
$rows = explode('&', $converted);
$output = array();
foreach($rows AS $k => $v){
   list($kk, $vv) = explode('=', $v);
   $output[ urldecode($kk) ] =  urldecode($vv);
}
return $output;
SequenceDigitale.com
quelle
1

Entschuldigen Sie das Nekrobumping, aber keine der bereitgestellten Antworten hat das getan, was ich intuitiv als "Abflachen eines mehrdimensionalen Arrays" verstanden habe. Nämlich dieser Fall:

[
  'a' => [
    'b' => 'value',
  ]
]

Alle bereitgestellten Lösungen würden es in nur reduzieren ['value'], aber das verliert Informationen über den Schlüssel und die Tiefe. Wenn Sie irgendwo anders einen anderen 'b'-Schlüssel haben, werden diese überschrieben.

Ich wollte ein Ergebnis wie dieses erzielen:

[
  'a_b' => 'value',
]

array_walk_recursive gibt die Informationen über den Schlüssel, den er gerade rekursiert, nicht weiter, also habe ich es mit einfacher Rekursion gemacht:

function flatten($array, $prefix = '') {
    $return = [];
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $return = array_merge($return, flatten($value, $prefix . $key . '_'));
        } else {
            $return[$prefix . $key] = $value;
        }
    }
    return $return;
}

Ändern Sie das Präfix $ und das Trennzeichen '_' nach Ihren Wünschen.

Spielplatz hier: https://3v4l.org/0B8hf

zzanzare
quelle
0

Einfacher Ansatz. Siehe Rekursion.

<?php

function flatten_array($simple){
static $outputs=array();
foreach ( $simple as $value)
{
if(is_array($value)){
    flatten_array($value);
}
else{
    $outputs[]=$value;
}

}
return $outputs;
}

$eg=['s'=>['p','n'=>['t']]];
$out=flatten_array($eg);
print_r($out);

?>
Paras Agarwal
quelle
Warum wird staticfür diese Aufgabe eine möglicherweise schlechte Idee verwendet? Unbeabsichtigte Vorratsdatenspeicherung. Dies wird Programmierer sicherlich überraschen, wenn sie dieses Verhalten nicht kennen / erwarten. Schauen Sie sich diese Demonstration an .
Mickmackusa
Sie haben eine "Nur-Code" -Antwort veröffentlicht - diese sind bei StackOverflow von geringem Wert, da sie das OP und zukünftige Forscher nicht ausbilden. Bitte nehmen Sie sich einen Moment Zeit, um diese Antwort zu verbessern, indem Sie angeben, wie Ihre Antwort funktioniert und warum Sie der Meinung sind, dass dies eine bessere Idee ist als die früheren Antworten.
Mickmackusa
0

Jemand könnte dies nützlich finden. Ich hatte ein Problem beim Reduzieren des Arrays in einer bestimmten Dimension. Ich würde es als letzte Dimension bezeichnen, wenn ich beispielsweise ein Array wie das folgende habe:

array (
  'germany' => 
  array (
    'cars' => 
    array (
      'bmw' => 
      array (
        0 => 'm4',
        1 => 'x3',
        2 => 'x8',
      ),
    ),
  ),
  'france' => 
  array (
    'cars' => 
    array (
      'peugeot' => 
      array (
        0 => '206',
        1 => '3008',
        2 => '5008',
      ),
    ),
  ),
)

Oder:

array (
  'earth' => 
  array (
    'germany' => 
    array (
      'cars' => 
      array (
        'bmw' => 
        array (
          0 => 'm4',
          1 => 'x3',
          2 => 'x8',
        ),
      ),
    ),
  ),
  'mars' => 
  array (
    'france' => 
    array (
      'cars' => 
      array (
        'peugeot' => 
        array (
          0 => '206',
          1 => '3008',
          2 => '5008',
        ),
      ),
    ),
  ),
)

Für diese beiden Arrays erhalte ich beim Aufrufen der folgenden Methode das folgende Ergebnis:

array (
  0 => 
  array (
    0 => 'm4',
    1 => 'x3',
    2 => 'x8',
  ),
  1 => 
  array (
    0 => '206',
    1 => '3008',
    2 => '5008',
  ),
)

Ich reduziere also auf die letzte Array-Dimension, die gleich bleiben sollte. Die folgende Methode könnte überarbeitet werden, um tatsächlich auf jeder Ebene anzuhalten:

function flattenAggregatedArray($aggregatedArray) {
    $final = $lvls = [];
    $counter = 1;
    $lvls[$counter] = $aggregatedArray;


    $elem = current($aggregatedArray);

    while ($elem){
        while(is_array($elem)){
            $counter++;
            $lvls[$counter] = $elem;
            $elem =  current($elem);
        }

        $final[] = $lvls[$counter];
        $elem = next($lvls[--$counter]);
        while ( $elem  == null){
            if (isset($lvls[$counter-1])){
                $elem = next($lvls[--$counter]);
            }
            else{
                return $final;
            }
        }
    }
}
ermacmkx
quelle
-1

Wenn Sie nur an den Werten für einen bestimmten Schlüssel interessiert sind, ist dieser Ansatz möglicherweise hilfreich:

function valuelist($array, $array_column) {
    $return = array();
    foreach($array AS $row){
        $return[]=$row[$array_column];
    };
    return $return;
};

Beispiel:

Gegeben $ get_role_action =

array(3) {
  [0]=>
  array(2) {
    ["ACTION_CD"]=>
    string(12) "ADD_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [1]=>
  array(2) {
    ["ACTION_CD"]=>
    string(13) "LINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [2]=>
  array(2) {
    ["ACTION_CD"]=>
    string(15) "UNLINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
}

als $variables['role_action_list']=valuelist($get_role_action, 'ACTION_CD');würde führen zu:

$variables["role_action_list"]=>
  array(3) {
    [0]=>
    string(12) "ADD_DOCUMENT"
    [1]=>
    string(13) "LINK_DOCUMENT"
    [2]=>
    string(15) "UNLINK_DOCUMENT"
  }

Von dort aus können Sie Wert-Lookups wie folgt durchführen:

if( in_array('ADD_DOCUMENT', $variables['role_action_list']) ){
    //do something
};
Jeromy Französisch
quelle
Dies ist ein PHP-Abbruch einer gleichnamigen CFML-Funktion.
Jeromy French
Ich habe abgelehnt, weil es die richtige Antwort auf die falsche Frage ist.
Mickmackusa
-1

irgendetwas davon hat bei mir nicht funktioniert ... also musste ich es selbst ausführen. funktioniert gut:

function arrayFlat($arr){
$out = '';
    foreach($arr as $key => $value){

        if(!is_array($value)){
            $out .= $value.',';
        }else{
            $out .= $key.',';
            $out .= arrayFlat($value);
        }

    }
    return trim($out,',');
}


$result = explode(',',arrayFlat($yourArray));
echo '<pre>';
print_r($result);
echo '</pre>';
VNicholson
quelle
Diese Nur-Code-Antwort funktioniert nicht wie gewünscht. 3v4l.org/U3bfp <- Proof Dies ist der Grund für meine Ablehnung.
Mickmackusa
-1

Wenn ein mehrdimensionales Array angegeben und in ein eindimensionales Array konvertiert wird, können Sie alle Werte mit Arrays deaktivieren und in der ersten Dimension speichern, z. B.:

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;
}
Kenorb
quelle
Ich habe diese Antwort abgelehnt, weil sie in keiner Version funktioniert. 3v4l.org/7cO9N (Proof) Auch each()von php7.2 veraltet.
Mickmackusa