Flatten Nested Arrays Using PHP
Written by David Walsh on Friday, August 22, 2008
While browing the MooTools 1.2 source code, I found Array’s flatten() method. The flatten() method takes nested arrays and “flattens” them all into one array. I asked myself how I could do that using PHP. The following is what I came up with.
The PHP
$myarray = array('a','b',array(array(array('x'),'y','z')),array(array('p')));
function array_flatten($array,$return)
{
for($x = 0; $x <= count($array); $x++)
{
if(is_array($array[$x]))
{
$return = array_flatten($array[$x],$return);
}
else
{
if($array[$x])
{
$return[] = $array[$x];
}
}
}
return $return;
}
$res = array_flatten($myarray,array());
The Result
Array
(
[0] => a
[1] => b
[2] => x
[3] => y
[4] => z
[5] => p
)
As you can see, array_flatten() is used recursively to sniff out values from the original array. While I don't believe I've ever found myself with an array as nested as my example, it's good to know that I can extract the values if necessary.
Epic Discussion
Be Heard!
I want to hear what you have to say! Share your comments and questions below.
Here is another function without the need for recursion.
function array_flatten($array, $maintain_keys=false) {
$array = print_r($array, true);
preg_match_all(“/[(.+?)].*?\=>(.+?)\n/”, $array, $matches);
$array = array();
foreach ($matches[0] as $k=>$v) {
$key = trim($matches[1][$k]);
$value = trim($matches[2][$k]);
if (preg_match(“/^array$/i”, $value)) continue;
if (array_key_exists($key, $array) || !$maintain_keys) {
$array[] = $value;
} else $array[$key] = $value;
}
return $array;
}
$arr = array(‘alpha’=>’a',’b',array(array(array(‘beta’=>’x'),’alpha’=>’y',’z')),array(array(‘p’)));
echo ” . print_r($arr, true) . ”;
echo ” . print_r(array_flatten($arr) , true) . ”;
echo ” . print_r(array_flatten($arr, true) , true) . ”;
Wonder if the array keys will be the same when used with mysql_fetch_assoc
I went through this same issue with python a couple years ago[1]. Strangely, in all my years of using php, I never really needed flatten (well maybe a couple times it would have been handy). Python doesn’t handle recursion very well, so an iterative version is pretty much a necessity for it to be of any use. Here is a php translation of the python version I ended up using:
function array_flatten ($array)
{
$i = 0;
while ($i < count ($array))
{
while (is_array ($array[$i]))
{
if (!$array[$i])
{
array_splice ($array, $i, 1);
--$i;
break;
}
else
{
array_splice ($array, $i, 1, $array[$i]);
}
}
++$i;
}
return $array;
}
It’s much slower than your implementation (I assume because of the overhead of array_splice compared to python’s list.pop, since the python version performs comparably yours–it just doesn’t grok 2000 levels of recursion. In fact, when I use a translation of your php version, python dies very soon with “maximum recursion depth exceeded”).
Ps. One small note, on 5.2.6 I get warnings about trying to accessing invalid indexes from the $array[$x] on lines 7 and 13–prefixing them with “@” prevents them from incurring the slowdown of invoking the warning of course (just thought I’d mention it for posterity).
__
[1] http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html
Replace line #5 from
for($x = 0; $x <= count($array); $x++)
to
for($x = 0; $x < count($array); $x++)
(<= become <)
otherwise you get a notice “error” (Undefined offset) for every array fetched by the function.
I did a different approach, since the requirement was also different, and the outcome is boasted
about at php-trivandrum, as function array_flatten
Thanks for the post, this function is very handy.
Although, as we are retrieving a new array with new indexes it might be nice to have the same function that can flatten an associative array.
Here is your function modified to work with associative array:
function array_flatten($array, $return=array()) {
foreach ($array AS $key => $value) {
if(is_array($value))
{
$return = array_flatten($value,$return);
}
else
{
if($value)
{
$return[] = $value;
}
}
}
return $return;
}
So $myarray = array(‘a’,'b’,array(array(‘test’ => array(‘x’),’y',’nested2′ => ‘z’)),array(‘nested3′ => array(‘p’))) will also work as expected.
David! You just saved me hours!