Flatten Nested Arrays Using PHP

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.


Comments

  1. Alan

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

  2. Harsha M V

    Wonder if the array keys will be the same when used with mysql_fetch_assoc

  3. MonkeeSage

    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

  4. Alexandre Valiquette

    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.

  5. php trivandrum

    I did a different approach, since the requirement was also different, and the outcome is boasted
    about at php-trivandrum, as function array_flatten

  6. Manu

    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.

  7. Chris the Developer

    David! You just saved me hours!

  8. Ennio Wolsink

    @Manu: if you replace $return[] = $value; with $return[$key] = $value; you get the preserve the index names of the source array(s). Don’t know if that’s everyone preference, but that was what I was looking for. If one wanted to make this optional, he could add a 3rd optional parameter to this function to indicate wether or not to preserve index names, like so:

    function array_flatten($array, $return=array(), $preserve_index_names = false) {

    foreach ($array AS $key => $value) {
    if(is_array($value)) {
    $return = array_flatten($value,$return, $preserve_index_names);
    }
    else {
    if($value) {
    if($preserve_index_names === false) {
    $return[] = $value;
    }
    else {
    $return[$key] = $value;
    }
    }
    }
    }

    return $return;
    }

    And then run it like so to get a flattened array back with index names preserved:

    $result = array_flatten($input, array(), true);

    And like this if you don’t want the index names preserved:

    $result = array_flatten($input);

  9. Mike

    Great function, thanks David.

  10. kavs

    This is what i use, sposed to be faster than most methods:

    function flattenArray(array $array){
    $ret_array = array();
    foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $value)
    {
    $ret_array[] = $value;
    }
    return $ret_array;
    }

  11. DkN

    NOTE: this function will omit zero values. for example:

    $test[0][0] = ’0′;
    $test[0][1] = ‘b’;

    $test[1][0] = ‘c’;
    $test[1][1] = ‘d’;

    array_flatten($test) will output:

    Array ( [0] => b [1] => c [2] => d )

    to fix this problem, on line 13 use:

    if(isset($array[$x]))

    instead of:

    if($array[$x])

    here’s the whole function with the line replaced:

    function array_flatten($array,$return=array())
    {
    for($x = 0; $x <= count($array); $x++)
    {
    if(is_array($array[$x]))
    {
    $return = array_flatten($array[$x],$return);
    }
    else
    {
    if(isset($array[$x]))
    {
    $return[] = $array[$x];
    }
    }
    }
    return $return;
    }

  12. Ralph Holzmann

    I know this post is a bit old, but here’s what I came up with – it’s super fast and concise.

    function array_flatten( $array ) {
    $arr = array();
    function flatten( $item, $key, $flattened ) {
    $flattened[] = $item;
    };
    array_walk_recursive($array, 'flatten', &$arr);
    return $arr;
    }

  13. Phil Freo

    Made a few improvements/simplifications, allowed associative arrays, etc.


    function array_flatten(array $array, array $return = array()) {

    foreach ($array as $k => $item) {
    if (is_array($item))
    $return = array_flatten($item, $return);
    elseif ($item)
    $return[] = $item;
    }

    return $return;
    }

  14. moli

    about the code on very top. their is an issue on using for loop, if the nested array have a key, it wont show the value. Instead use foreach loop. I have some revised on the code above, I hope it will help.

    function array_flatten($array, $return)
    {

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

    $test= array(‘ddd’,
    array(“hello” => ‘one’,'two’,array(array(‘inner’=>’innerval’, ‘innerval2′,array(‘key_inner’=>’inner_inner’)))),’ccc’,
    array(‘a’,'b’),
    array(‘dog’,'cat’)
    );
    $result = array_flatten($test,array());
    print_r($result);

    Output:
    Array
    (
    [0] => ddd
    [1] => one
    [2] => two
    [3] => innerval
    [4] => innerval2
    [5] => inner_inner
    [6] => ccc
    [7] => a
    [8] => b
    [9] => dog
    [10] => cat
    )


Be Heard!

Share your thoughts without being a jerk! And wrap your code in <code> tags, f00!

Name*:
Email*:
Website: