357 votes

Comment aplatir un tableau multidimensionnel ?

Est-il possible, en PHP, de aplatir un tableau (bi/multi)dimensionnel sans utiliser de récursivité ou de références ?

Je suis seulement intéressé par les valeurs donc les clés peuvent être ignorées, je pense dans le sens de array_map() et array_values().

17 votes

Pourquoi éviter la récursivité?

5 votes

4 votes

Vous ne pouvez rien faire avec tous les éléments d'arrays d'une profondeur arbitraire sans récursion (vous pouvez le déguiser en itération, mais pomme de terre, potahto.) Si vous voulez simplement éviter d'écrire le code de gestion de la récursion vous-même, utilisez dk2.php.net/manual/en/function.array-walk-recursive.php avec un rappel qui ajoute l'élément à un tableau disponible (utilisez global, le paramètre userdata, mettez tout dans une classe et faites référence à $this, etc.)

352voto

too much php Points 27983

À partir de PHP 5.3, la solution la plus courte semble être array_walk_recursive() avec la nouvelle syntaxe des fermetures :

function flatten(array $array) {
    $return = array();
    array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
    return $return;
}

40 votes

Si vous souhaitez des clés, fonctionnez à plat (array $array) { $return = array(); array_walk_recursive($array, function($a,$b) use (&$return) { $return[$b] = $a; }); return $return; }

0 votes

Pouvez-vous réécrire ceci pour l'utiliser avec php 5.2?

2 votes

@Alex malheureusement, vous avez besoin de la syntaxe use pour que cela fonctionne avec array_walk_recursive car il n'accepte pas le paramètre facultatif $userdata par référence

326voto

VolkerK Points 54118

Vous pouvez utiliser la Standard PHP Library (SPL) pour "cacher" la récursion.

$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, " ";
}

imprime

1 2 3 4 5 6 7 8 9

428 votes

Suis-je le seul à penser que 'RecursiveIteratorIterator' est un nom ridicule?

53 votes

C'est plus "logique" que "accrocheur". Tout ne peut pas avoir un nom fantastique comme JOGL, Knol ou Azure :-)

9 votes

Cela ne fonctionnera pas pour les tableaux vides en tant qu'enfants. Ils seront renvoyés en tant que parent.

100voto

Prasanth Bendra Points 9618

Solution pour tableau à 2 dimensions

Veuillez essayer ceci :

$array  = votre tableau

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

echo "

0 votes

Merci, le premier a fonctionné sur un tableau que je recevais de PDO alors que les autres solutions ne fonctionnaient pas.

7 votes

C'est une mauvaise stratégie. call_user_func_array('array_merge', []) (remarquez le tableau vide) renvoie null et déclenche une erreur d'avertissement php. C'est une solution astucieuse si vous savez que votre tableau ne sera pas vide, mais ce n'est pas une supposition commune que beaucoup peuvent faire.

0 votes

Le OP a spécifiquement demandé des solutions non récursives.

29voto

hakre Points 102271

Pour aplatir sans récursion (comme vous l'avez demandé), vous pouvez utiliser une pile. Naturellement, vous pouvez mettre cela dans une fonction à part comme array_flatten. Voici une version qui fonctionne sans clés :

function array_flatten(array $array)
{
    $flat = array(); // initialiser le tableau de retour
    $stack = array_values($array); // initialiser la pile
    while($stack) // traiter la pile jusqu'à la fin
    {
        $value = array_shift($stack);
        if (is_array($value)) // une valeur à traiter davantage
        {
            array_unshift($stack, ...$value);
        }
        else // une valeur à prendre
        {
            $flat[] = $value;
        }
    }
    return $flat;
}

Les éléments sont traités dans leur ordre. Comme les sous-éléments seront déplacés en haut de la pile, ils seront traités ensuite.

Il est possible de prendre en compte les clés également, cependant, vous aurez besoin d'une stratégie différente pour gérer la pile. Cela est nécessaire car vous devez traiter les clés en double possibles dans les sous-tableaux. Une réponse similaire dans une question connexe : PHP Parcourir un tableau multidimensionnel tout en préservant les clés

Je ne suis pas spécifiquement sûr, mais je l'avais testé dans le passé : Le RecurisiveIterator utilise la récursion, donc cela dépend de ce dont vous avez vraiment besoin. Il devrait être possible de créer un itérateur récursif basé sur des piles également :

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

Démo

Je n'ai pas encore eu le temps d'implémenter la pile basée sur RecursiveIterator ce qui je pense est une bonne idée.

0 votes

+1 pour la fonction "array_flatten" exceptionnelle. J'ai dû ajouter if(!empty($value)){$flat[] = $value} à l'intérieur de la déclaration else pour éviter que les éléments vides ne soient ajoutés au tableau de résultats. Fonction incroyable !

1 votes

L'opération d'aplatissage peut être réduite de $stack = array_merge(array_values($value), $stack); à array_unshift($stack, ...$value); et l'appel de array_values() est probablement superflu pour la plupart, mais il ne semblait pas approprié de modifier la réponse étant donné qu'elle précède la version 5.6.

0 votes

@Walf : Oui, c'est la seule raison. Merci pour l'astuce, j'ai modifié ça.

18voto

nilamo Points 1341

Utilise la récursion. Espérons qu'une fois que vous aurez vu à quel point elle n'est pas complexe, votre peur de la récursion se dissipera.

function flatten($array) {
    if (!is_array($array)) {
        // rien à faire si ce n'est pas un tableau
        return array($array);
    }

    $result = array();
    foreach ($array as $value) {
        // diviser le sous-tableau et ajouter les parties
        $result = array_merge($result, flatten($value));
    }

    return $result;
}

$arr = array('foo', array('nobody', 'expects', array('another', 'level'), 'the', 'Spanish', 'Inquisition'), 'bar');
echo '

Résultat:

1 votes

Je ne crains pas la récursivité, je veux juste apprendre d'autres façons de faire la même chose.

13 votes

+1 pour cette récursivité : Espérons qu'en voyant à quel point ce n'est pas complexe, votre peur de la récursivité disparaîtra une fois que vous verrez à quel point ce n'est pas complexe.

1 votes

D'accord, c'est au-dessus de moi. Comment est-il possible que la réponse ("Je ne crains pas la récursion") ait trois ans et demi de plus (24 août '09) que l'énoncé initial ("(...) votre peur de la récursion va disparaître (...)") fait le 5 février '13?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X