# [Solved] How to Flatten a Multidimensional Array?

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().

## Solution #1:

You can use the 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 #2:

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 #3:

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:

Solution for 2 dimensional 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;
}

\$result = array_flatten(\$array);

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

## Solution #5:

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) \$valuen";
}

Demo

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

## Solution #6:

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

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

## Solution #7:

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 #8:

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:

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:

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:

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 #12:

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 (
array (
'und' =>
array (
0 =>
array (
'first_name' => 'First name',
'last_name' => 'Last name',
'locality' => 'Town/City',
'postal_code' => 'Postcode',
),
),
),
),
),
),
)

you get:

array (
'first_name' => 'First name',
'last_name' => 'Last name',
'locality' => 'Town/City',
'postal_code' => 'Postcode',
)

## Solution #13:

You can do it with ouzo goodies:

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

See: Here

## Solution #14:

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 #15:

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: rn";
print_r(\$recursive);
\$flat = null;
flatten_array(\$recursive, \$flat);

echo "Flat: rn";
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:rn";
echo implode(',',\$flat);

## Solution #16:

/**
* 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 #17:

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 #18:

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:

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 #20:

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 #21:

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 #22:

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 #23:

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 #24:

<?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 #25:

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

## Solution #26:

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

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

Prints

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

## Solution #27:

Just posting a some else solution)

function flatMultidimensionalArray(array &\$_arr): array
{
\$result = [];
array_walk_recursive(\$_arr, static function (&\$value, &\$key) use (&\$result) {
\$result[\$key] = \$value;
});

return \$result;
}

## Solution #28:

For those who just need to join one level below at the top.

Being clearer, how transform this:

Array
(
[0] => Array
(
[0] => Array
(
[id] => 001
)
[1] => Array
(
[id] => 005
)
)
[1] => Array
(
[0] => Array
(
[id] => 007
)
[1] => Array
(
[id] => 009
)
)
)

On this:

Array
(
[0] => Array
(
[0] => Array
(
[id] => 001
)
[1] => Array
(
[id] => 005
)
[2] => Array
(
[id] => 007
)
[3] => Array
(
[id] => 009
)
)
)

The (simple) code:

foreach (\$multi_array as \$key => \$reduced_array) {
foreach (\$reduced_array as \$key => \$value) {
\$new_array[] = \$value;
}
}

With so many functions available, sometimes we forget that we can do something with a simple code …

## Solution #29:

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 #30:

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

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .