Comment Aplatir un Tableau Multidimensionnel?

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

je suis seulement intéressé par les valeurs de sorte que les clés peuvent être ignorées, je pense dans les lignes de array_map() et array_values() .

194
demandé sur BoltClock 2009-08-24 03:47:25

24 réponses

vous pouvez utiliser la Standard PHP Library (SPL) pour" masquer " 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 
223
répondu VolkerK 2009-08-24 02:39:06

à partir de PHP 5.3 la solution la plus courte semble être array_walk_recursive() avec la nouvelle syntaxe de fermeture:

function flatten(array $array) {
    $return = array();
    array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
    return $return;
}
247
répondu too much php 2009-08-24 01:59:35

Solution pour les 2 dimensions de la matrice de

s'il vous Plaît essayez ce qui suit :

$array  = your array

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

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

EDIT: 21-Aug-13

Voici la solution qui fonctionne pour le tableau multidimensionnel:

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

Réf: http://php.net/manual/en/function.call-user-func-array.php

68
répondu Prasanth Bendra 2015-04-20 16:26:12

pour aplatir la récursion sans/sans (comme vous l'avez demandé), Vous pouvez utiliser un stack . Naturellement, vous pouvez mettre cela dans une fonction propre comme array_flatten . Ce qui suit est une version qui fonctionne w/o touches:.

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;
}
Les éléments

sont traités dans leur ordre. Parce que les sous-éléments seront déplacés sur le dessus de la pile, ils seront traités ensuite.

il est possible de prendre des clés en compte aussi, cependant, vous aurez besoin d'un autre stratégie pour gérer la pile. Cela est nécessaire parce que vous avez besoin de traiter avec des clés dupliquées possibles dans les sous-tableaux. Une semblable réponse à une question connexe: PHP Promenade à travers tableau multidimensionnel, tout en préservant les touches

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

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

Démo

Je ne l'ai pas fait jusqu'à présent, pour mettre en œuvre la pile basée sur RecursiveIterator qui je pense est une bonne idée.

23
répondu hakre 2017-05-23 12:34:45

utilise la récursion. Avec un peu de chance, en voyant à quel point ce n'est pas Complexe, votre peur de la récursion se dissipera une fois que vous verrez à quel point ce n'est pas complexe.

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

sortie:

<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>
16
répondu nilamo 2012-01-08 19:40:52

j'ai juste pensé que je ferais remarquer que c'est un pli, donc array_reduce peut être utilisé:

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

EDIT: notez que cela peut être composé pour aplatir n'importe quel nombre de niveaux. Nous pouvons le faire de plusieurs façons:

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

bien sûr, nous pourrions aussi utiliser des boucles, mais la question demande une fonction combinatrice dans le sens de array_map ou array_values.

14
répondu Warbo 2013-07-19 14:29:04

Simple et One-liner réponse.

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

Utilisation:

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

print_r( flatten_array($array) );

sortie (en PsySH):

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

maintenant c'est plutôt à vous maintenant comment vous allez manipuler les clés. Cheers


modifier (2017-03-01)

, Citant Nigel alderton a préoccupation ou question:

juste pour clarifier, cela préserve les clés (même numériques) de sorte que les valeurs qui ont la même clé sont perdues. Par exemple $array = ['a',['b','c']] devient Array ([0] => b, [1] => c ) . Le 'a' est perdu parce que 'b' a également une clé de 0

Citant Svish réponse:

il suffit d'ajouter false comme second paramètre ($use_keys) au iterator_to_array call

13
répondu Allen Linatoc 2017-05-23 11:55:10

en PHP 5.6 et au-dessus vous pouvez aplatir des tableaux bidimensionnels avec array_merge après avoir déballé le tableau extérieur avec ... opérateur. Le code est simple et clair.

$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
)

mais il ne fonctionne pas lorsque le tableau extérieur a des clés non numériques. Dans ce cas, vous devrez d'abord appeler array_values .

$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
)
8
répondu Joyce Babu 2017-10-21 09:41:08

cette solution n'est pas récursive. Notez que l'ordre des éléments est un peu mélangé.

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;
}
4
répondu too much php 2009-08-24 01:15:26

aplatit uniquement les tableaux bidimensionnels:

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

// Result: [1, 2, 3, 4]
4
répondu artnikpro 2016-11-23 13:21:20

essayez la fonction simple suivante:

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

ainsi de ceci:

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',
            ),
          ),
        ),
      ),
    ),
  ),
)

, vous obtenez:

array (
  'first_name' => 'First name',
  'last_name' => 'Last name',
  'thoroughfare' => 'Address 1',
  'premise' => 'Address 2',
  'locality' => 'Town/City',
  'administrative_area' => 'County',
  'postal_code' => 'Postcode',
)
3
répondu kenorb 2015-11-02 18:41:27

je crois que c'est la solution la plus propre sans utiliser de mutations ou de classes inconnues.

<?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));
3
répondu Dariush Alipour 2017-10-10 11:58:33

le truc est de passer à la fois les tableaux source et destination par référence.

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);
2
répondu Rick Garcia 2012-11-04 19:31:33
/**
 * 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));
    }
);

Gist "extrait de 151930920"

2
répondu Arsham 2013-08-26 09:52:52

vous pouvez le faire avec ouzo goodies :

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

Voir: Ici

2
répondu woru 2017-02-06 09:40:17

si vous n'aimez pas la récursion ... essayez de déplacer la place :)

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

Note: dans cette version simple, cela ne supporte pas les touches array.

2
répondu BurninLeo 2018-01-29 21:24:03

pour 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;
}
1
répondu Alexei T 2012-07-04 15:19:22

cette version peut faire profond, peu profond, ou un nombre spécifique de niveaux:

/**
 * @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;
}
1
répondu ryanve 2013-03-07 08:41:38

parce que le code dans ici semble effrayant. Voici une fonction qui convertira également un tableau multidimensionnel en une syntaxe compatible html form, mais qui est plus facile à lire.

/**
 * 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;
}
1
répondu Gellweiler 2017-05-23 11:55:10

C'est ma solution, en utilisant une référence:

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>";
0
répondu Martyn Shutt 2015-09-19 13:33:54
<?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;
}
?>
0
répondu Furqan Freed 2017-03-29 06:01:37

Voici une approche simpliste:

$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);
0
répondu Jack Nicholson 2017-10-19 12:28:36

j'avais besoin de représenter le tableau multidimensionnel de PHP en format HTML.

$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"
}
-1
répondu Gajus 2013-09-30 04:55:13

si vous avez un tableau d'objets et que vous voulez l'aplatir avec un noeud, utilisez simplement cette fonction:

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;
}
-1
répondu حسین شکرزاده 2015-03-23 14:23:57