How to Flatten a Multidimensional Array?

PhpArraysMultidimensional ArrayFlatten

Php Problem Overview


Is it possible, in PHP, to flatten a (bi/multi)dimensional array without using recursion or references?

I'm only interested in the values so the keys can be ignored, I'm thinking in the lines of array_map() and array_values().

Php Solutions


Solution 1 - Php

As of PHP 5.3 the shortest solution seems to be array_walk_recursive() with the new closures syntax:

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

Solution 2 - Php

You can use the http://uk.php.net/spl">Standard PHP Library (SPL) to "hide" the recursion.

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

prints

1 2 3 4 5 6 7 8 9 

Solution 3 - Php

In PHP 5.6 and above you can flatten two dimensional arrays with array_merge after unpacking the outer array with ... operator. The code is simple and clear.

array_merge(...$a);

This works with collection of associative arrays too.

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

In PHP 8.0 and below, array unpacking does not work when the outer array has non numeric keys. Support for unpacking array with string keys is available from PHP 8.1. To support 8.0 and below, you should call array_values first.

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

Update: Based on comment by @MohamedGharib

This will throw an error if the outer array is empty, since array_merge would be called with zero arguments. It can be be avoided by adding an empty array as the first argument.

array_merge([], ...$a);

Solution 4 - Php

Solution for 2 dimensional array

Please try this :

$array  = your array

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

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

EDIT : 21-Aug-13

Here is the solution which works for multi-dimensional 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);

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

Solution 5 - Php

To flatten w/o recursion (as you have asked for), you can use a stack. Naturally you can put this into a function of it's own like array_flatten. The following is a version that works w/o keys:.

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
        {
            array_unshift($stack, ...$value);
        }
        else // a value to take
        {
            $flat[] = $value;
        }
    }
    return $flat;
}

Elements are processed in their order. Because subelements will be moved on top of the stack, they will be processed next.

It's possible to take keys into account as well, however, you'll need a different strategy to handle the stack. That's needed because you need to deal with possible duplicate keys in the sub-arrays. A similar answer in a related question: PHP Walk through multidimensional array while preserving keys

I'm not specifically sure, but I I had tested this in the past: The RecurisiveIterator does use recursion, so it depends on what you really need. Should be possible to create a recursive iterator based on stacks as well:

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

Demo

I didn't make it so far, to implement the stack based on RecursiveIterator which I think is a nice idea.

Solution 6 - Php

Just thought I'd point out that this is a fold, so array_reduce can be used:

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

EDIT: Note that this can be composed to flatten any number of levels. We can do this in several ways:

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

Of course, we could also use loops but the question asks for a combinator function along the lines of array_map or array_values.

Solution 7 - Php

Straightforward and One-liner answer.

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

Usage:

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

print_r( flatten_array($array) );

Output (in PsySH):

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

Now it's pretty up to you now how you'll handle the keys. Cheers


EDIT (2017-03-01)

Quoting Nigel Alderton's concern/issue:

> Just to clarify, this preserves keys (even numeric ones) so values that have the same key are lost. For example $array = ['a',['b','c']] becomes Array ([0] => b, [1] => c ). The 'a' is lost because 'b' also has a key of 0

Quoting Svish's answer:

> Just add false as second parameter ($use_keys) to the iterator_to_array call

Solution 8 - Php

Uses recursion. Hopefully upon seeing how not-complex it is, your fear of recursion will dissipate once you see how not-complex it is.

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

Output:

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

Solution 9 - Php

Flattens two dimensional arrays only:

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

// Result: [1, 2, 3, 4]

Solution 10 - Php

This solution is non-recursive. Note that the order of the elements will be somewhat mixed.

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

Solution 11 - Php

The Laravel helper for flattening arrays is Arr::flatten()

Solution 12 - Php

I believe this is the cleanest solution without using any mutations nor unfamiliar classes.

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

Solution 13 - Php

You can do it with ouzo goodies:

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

See: Here

Solution 14 - Php

Try the following simple function:

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

So from this:

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

you get:

array (
  'first_name' => 'First name',
  'last_name' => 'Last name',
  'thoroughfare' => 'Address 1',
  'premise' => 'Address 2',
  'locality' => 'Town/City',
  'administrative_area' => 'County',
  'postal_code' => 'Postcode',
)

Solution 15 - Php

The trick is passing the both the source and destination arrays by reference.

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

Solution 16 - Php

If you really don't like a recursion ... try shifting instead :)

$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: In this simple version, this does not support array keys.

Solution 17 - Php

How about using a recursive generator? https://ideone.com/d0TXCg

<?php

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

foreach (iterate($array) as $item) {
	var_dump($item);
};

function iterate($array)
{
	foreach ($array as $item) {
		if (is_array($item)) {
			yield from iterate($item);
		} else {
        	yield $item;
		}
	}
}

Solution 18 - Php

If you want to keep also your keys that is solution.

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

Unfortunately it outputs only final nested arrays, without middle keys. So for the following example:

$array = array(
    'sweet' => array(
        'a' => 'apple',
        'b' => 'banana'),
    'sour' => 'lemon'); 
print_r(flatten($fruits));

Output is:

Array
(
    [a] => apple
    [b] => banana
    [sour] => lemon
)

Solution 19 - Php

/**
 * 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 snippet

Solution 20 - Php

This can be achieved by using array_walk_recursive

$a = array(1,2,array(3,4, array(5,6,7), 8), 9);
array_walk_recursive($a, function($v) use (&$r){$r[]=$v;});
print_r($r);

Working example :- https://3v4l.org/FpIrG

Solution 21 - Php

From PHP v7.4, you can use the spread operator and merge the arrays. Simple and effective.

$flatArr = array_merge(...$originalArray);

Solution 22 - Php

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

Solution 23 - Php

This version can do deep, shallow, or a specific number of levels:

/**
 * @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;
}

Solution 24 - Php

Because the code in here looks scary. Here is a function that will also convert a multidimensional array into html form compatible syntax, but which is easier to read.

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

Solution 25 - Php

Anyone looking for a really clean solution to this; here's an option:

Taking an array of arrays with various key value configurations:

$test_array = array(
    array('test' => 0, 0, 0, 0),
    array(0, 0, 'merp' => array('herp' => 'derp'), 0),
    array(0, 0, 0, 0),
    array(0, 0, 0, 0)
);
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($test_array));
var_dump( iterator_to_array($it, false) ) ; 

This will take only the values from each array and return a single flat array.

Output of values in result:

0 0 0 0 0 0 derp 0 0 0 0 0 0 0 0 0

Solution 26 - Php

If you want to keep intermediate keys:

function flattenArray(array &$result, $value, string $key = "")
{
    if (!is_array($value)) {
        $result[$key] = $value;
        return $result;
    }
    foreach ($value as $subKey => $subArray) {
        $newKey = $key !== "" ? $key . "_" . $subKey : $subKey;
        flattenArray($result, $subArray, $newKey);
    }
    return $result;
}

$nestedArray = [
    "name" => "John",
    "pets" => [
        ["id" => 1, "name" => "snooop"],
        ["id" => 2, "name" => "medor"],
    ],
    "job" => ["title" => "developper"],
];

$intermediateResult = [];
$flattened = flattenArray($intermediateResult, $nestedArray);
var_dump($flattened);

This will output:

array(6) {
["name"]=>
  string(4) "John"
        ["pets_0_id"]=>
  int(1)
  ["pets_0_name"]=>
  string(6) "snooop"
        ["pets_1_id"]=>
  int(2)
  ["pets_1_name"]=>
  string(5) "medor"
        ["job_title"]=>
  string(10) "developper"
}

See https://ideone.com/KXLtzZ#stdout

Solution 27 - Php

I needed to represent PHP multidimensional array in HTML input format.

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

Solution 28 - Php

If you have an array of objects and want to flatten it with a node, just use this function:

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

Solution 29 - Php

This is my solution, using a reference:

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

Solution 30 - Php

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

Solution 31 - Php

Here's a simplistic approach:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlix AxelView Question on Stackoverflow
Solution 1 - Phptoo much phpView Answer on Stackoverflow
Solution 2 - PhpVolkerKView Answer on Stackoverflow
Solution 3 - PhpJoyce BabuView Answer on Stackoverflow
Solution 4 - PhpPrasanth BendraView Answer on Stackoverflow
Solution 5 - PhphakreView Answer on Stackoverflow
Solution 6 - PhpWarboView Answer on Stackoverflow
Solution 7 - PhpAllen LinatocView Answer on Stackoverflow
Solution 8 - PhpnilamoView Answer on Stackoverflow
Solution 9 - PhpartnikproView Answer on Stackoverflow
Solution 10 - Phptoo much phpView Answer on Stackoverflow
Solution 11 - PhpMahoor13View Answer on Stackoverflow
Solution 12 - PhpDariush AlipourView Answer on Stackoverflow
Solution 13 - PhpworuView Answer on Stackoverflow
Solution 14 - PhpkenorbView Answer on Stackoverflow
Solution 15 - PhpRick GarciaView Answer on Stackoverflow
Solution 16 - PhpBurninLeoView Answer on Stackoverflow
Solution 17 - PhpAndriyView Answer on Stackoverflow
Solution 18 - PhpJsowaView Answer on Stackoverflow
Solution 19 - PhpArshamView Answer on Stackoverflow
Solution 20 - PhpRakesh JakharView Answer on Stackoverflow
Solution 21 - PhpRobert YeomansView Answer on Stackoverflow
Solution 22 - PhpAlexei TView Answer on Stackoverflow
Solution 23 - PhpryanveView Answer on Stackoverflow
Solution 24 - PhpGellweilerView Answer on Stackoverflow
Solution 25 - PhpLewisView Answer on Stackoverflow
Solution 26 - PhpThykofView Answer on Stackoverflow
Solution 27 - PhpGajusView Answer on Stackoverflow
Solution 28 - Phpحسین شکرزادهView Answer on Stackoverflow
Solution 29 - PhpMartyn ShuttView Answer on Stackoverflow
Solution 30 - PhpFurqan FreedView Answer on Stackoverflow
Solution 31 - PhpJackView Answer on Stackoverflow