98

It's probably beginner question but I'm going through documentation for longer time already and I can't find any solution. I thought I could use implode for each dimension and then put those strings back together with str_split to make new simple array. However I never know if the join pattern isn't also in values and so after doing str_split my original values could break.

Is there something like combine($array1, $array2) for arrays inside of multi-dimensional array?

3

23 Answers 23

151
$array  = your array

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

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

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

Here is another solution (works with 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);
Sign up to request clarification or add additional context in comments.

4 Comments

This answer is much faster than the accepted answer.
Since php5.3 you can now use the splat operator: $result = array_merge(...$array); php.net/manual/en/…
Your first answer doesn't work with a multi-dimensional array. 3v4l.org/tY8vD
And the second snippet fails on this simple example -- it destroys data while pushing into the result.
74

This is a one line, SUPER easy to use:

$result = array();
array_walk_recursive($original_array,function($v) use (&$result){ $result[] = $v; });

It is very easy to understand, inside the anonymous function/closure. $v is the value of your $original_array.

1 Comment

This is the only one that worked for me in a two level array.
44

Use array_walk_recursive

<?php

$aNonFlat = array(
    1,
    2,
    array(
        3,
        4,
        5,
        array(
            6,
            7
        ),
        8,
        9,
    ),
    10,
    11
);

$objTmp = (object) array('aFlat' => array());

array_walk_recursive($aNonFlat, create_function('&$v, $k, &$t', '$t->aFlat[] = $v;'), $objTmp);

var_dump($objTmp->aFlat);

/*
array(11) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
  [5]=>
  int(6)
  [6]=>
  int(7)
  [7]=>
  int(8)
  [8]=>
  int(9)
  [9]=>
  int(10)
  [10]=>
  int(11)
}
*/

?>

Tested with PHP 5.5.9-1ubuntu4.24 (cli) (built: Mar 16 2018 12:32:06)

9 Comments

Does anyone know why this doesn't work unless I use the (depreciated) call-time pass by reference. i.e. array_walk_recursive($array, create_function('&$v, $k, &$t', '$t[] = $v;'), &$flattened); The function definition is correctly defined as pass by reference. but doesn't work unless I pass by reference during call-time.
@jskilski Objects ($objTmp in this example) are passed by reference automatically; arrays are not. Try using an anonymous function (php.net/manual/en/functions.anonymous.php) instead of create_function.
this doesnt work in php 5.3.3 due to a bug in array_walk_recursive - bugs.php.net/bug.php?id=52719
@crazyphoton The kink says also This bug has been fixed in SVN.
Why does this answer mention using array_values()? I can't see any use of that function involved in the answer at all.
|
40

If you specifically have an array of arrays that doesn't go further than one level deep (a use case I find common) you can get away with array_merge and the splat operator.

<?php

$notFlat = [[1,2],[3,4]];
$flat = array_merge(...$notFlat);
var_dump($flat);

Output:

array(4) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
}

The splat operator effectively changes the array of arrays to a list of arrays as arguments for array_merge.

2 Comments

This looks like the best answer to me. It won't work with string keys, but can be easily modified to do so: $flat = array_merge( array_keys( $notFlat ), ...array_values( $notFlat ) );
Worth noting that this only works in PHP 7.4+
19
// $array = your multidimensional array

$flat_array = array();

foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $k=>$v){

$flat_array[$k] = $v;

}

Also documented: http://www.phpro.org/examples/Flatten-Array.html

3 Comments

Note: Only use for arrays of primitives. "RecursiveArrayIterator treats all objects as having children, and tries to recurse into them." php.net/manual/en/class.recursivearrayiterator.php#106519
@hakre: +1 agreed: adding iterator_to_array() to this answer would negate the need for the foreach loop. It could be a simple one-liner function. (albeit a somewhat long one-line)
I know this is old but still useful, however the $k needs to be replaced by something unique, such as a counter. Just using $k causes elements to be removed if the names are the same in inner arrays as the main one.
11

Sorry for necrobumping, but none of the provided answers did what I intuitively understood as "flattening a multidimensional array". Namely this case:

[
  'a' => [
    'b' => 'value',
  ]
]

all of the provided solutions would flatten it into just ['value'], but that loses information about the key and the depth, plus if you have another 'b' key somewhere else, it will overwrite them.

I wanted to get a result like this:

[
  'a_b' => 'value',
]

array_walk_recursive doesn't pass the information about the key it's currently recursing, so I did it with just plain recursion:

function flatten($array, $prefix = '') {
    $return = [];
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $return = array_merge($return, flatten($value, $prefix . $key . '_'));
        } else {
            $return[$prefix . $key] = $value;
        }
    }
    return $return;
}

Modify the $prefix and '_' separator to your liking.

Playground here: https://3v4l.org/0B8hf

1 Comment

It appears that you want a different behavior versus what is being asked in this question. You want to create string keys which represent the path to the original value. There are probably better pages to post this answer on.
6

With PHP 7, you can use generators and generator delegation (yield from) to flatten an array:

function array_flatten_iterator (array $array) {
    foreach ($array as $value) {
        if (is_array($value)) {
            yield from array_flatten_iterator($value);
        } else {
            yield $value;
        }
    }
}

function array_flatten (array $array) {
    return iterator_to_array(array_flatten_iterator($array), false);
}

Example:

$array = [
    1,
    2,
    [
        3,
        4,
        5,
        [
            6,
            7
        ],
        8,
        9,
    ],
    10,
    11,
];    

var_dump(array_flatten($array));

http://3v4l.org/RU30W

Comments

5

A non-recursive solution (but order-destroying):

function flatten($ar) {
    $toflat = array($ar);
    $res = array();

    while (($r = array_shift($toflat)) !== NULL) {
        foreach ($r as $v) {
            if (is_array($v)) {
                $toflat[] = $v;
            } else {
                $res[] = $v;
            }
        }
    }

    return $res;
}

Comments

5
function flatten_array($array, $preserve_keys = 0, &$out = array()) {
    # Flatten a multidimensional array to one dimension, optionally preserving keys.
    #
    # $array - the array to flatten
    # $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
    # $out - internal use argument for recursion
    foreach($array as $key => $child)
        if(is_array($child))
            $out = flatten_array($child, $preserve_keys, $out);
        elseif($preserve_keys + is_string($key) > 1)
            $out[$key] = $child;
        else
            $out[] = $child;
    return $out;
}

1 Comment

Sorry but it doesn't seem to handle multidimensional arrays properly - Demo
5

Another method from PHP's user comments (simplified) and here:

function array_flatten_recursive($array) { 
   if (!$array) return false;
   $flat = array();
   $RII = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
   foreach ($RII as $value) $flat[] = $value;
   return $flat;
}

The big benefit of this method is that it tracks the depth of the recursion, should you need that while flattening.
This will output:

$array = array( 
    'A' => array('B' => array( 1, 2, 3)), 
    'C' => array(4, 5) 
); 
print_r(array_flatten_recursive($array)); 

#Returns: 
Array ( 
    [0] => 1 
    [1] => 2 
    [2] => 3 
    [3] => 4 
    [4] => 5 
)

1 Comment

Note: Only use for arrays of primitives. "RecursiveArrayIterator treats all objects as having children, and tries to recurse into them." php.net/manual/en/class.recursivearrayiterator.php#106519
4

In PHP>=5.3 and based on Luc M's answer (the first one) you can make use of closures like this

array_walk_recursive($aNonFlat, function(&$v, $k, &$t){$t->aFlat[] = $v;}, $objTmp);

I love this because I don't have to surround the function's code with quotes like when using create_function()

2 Comments

if you're using anonymous functions, you might as well use a captured closure variable directly rather than this objTemp stuff
There is a bug in PHP5.3.3 which causes this to crash - bugs.php.net/bug.php?id=52719
2

Using higher-order functions (note: I'm using inline anonymous functions, which appeared in PHP 5.3):

function array_flatten($array) {
    return array_reduce(
        $array,
        function($prev, $element) {
            if (!is_array($element))
                $prev[] = $element;
            else
                $prev = array_merge($prev, array_flatten($element));
            return $prev;
        },
        array()
    );
}

Comments

2

I found a simple way to convert multilevel array into one. I use the function "http_build_query" which converts the array into a url string. Then, split the string with explode and decode the value.

Here is a sample.

$converted = http_build_query($data);
$rows = explode('&', $converted);
$output = array();
foreach($rows AS $k => $v){
   list($kk, $vv) = explode('=', $v);
   $output[ urldecode($kk) ] =  urldecode($vv);
}
return $output;

Comments

1

A new approach based on the previous example function submited by chaos, which fixes the bug of overwritting string keys in multiarrays:

# Flatten a multidimensional array to one dimension, optionally preserving keys.
# $array - the array to flatten
# $preserve_keys - 0 (default) to not preserve keys, 1 to preserve string keys only, 2 to preserve all keys
# $out - internal use argument for recursion

function flatten_array($array, $preserve_keys = 2, &$out = array(), &$last_subarray_found) 
{
        foreach($array as $key => $child)
        {
            if(is_array($child))
            {
                $last_subarray_found = $key;
                $out = flatten_array($child, $preserve_keys, $out, $last_subarray_found);
            }
            elseif($preserve_keys + is_string($key) > 1)
            {
                if ($last_subarray_found)
                {
                    $sfinal_key_value = $last_subarray_found . "_" . $key;
                }
                else
                {
                    $sfinal_key_value = $key;
                }
                $out[$sfinal_key_value] = $child;
            }
            else
            {
                $out[] = $child;
            }
        }

        return $out;
}

Example:
$newarraytest = array();
$last_subarray_found = "";
$this->flatten_array($array, 2, $newarraytest, $last_subarray_found);

Comments

1
/*consider $mArray as multidimensional array and $sArray as single dimensional array
this code will ignore the parent array
*/

function flatten_array2($mArray) {
    $sArray = array();

    foreach ($mArray as $row) {
        if ( !(is_array($row)) ) {
            if($sArray[] = $row){
            }
        } else {
            $sArray = array_merge($sArray,flatten_array2($row));
        }
    }
    return $sArray;
}

Comments

1

you can try this:

function flat_an_array($a)
{
    foreach($a as $i)
    {
        if(is_array($i)) 
        {
            if($na) $na = array_merge($na,flat_an_array($i));
            else $na = flat_an_array($i);
        }
        else $na[] = $i;
    }
    return $na;
}

Comments

1

If you're okay with loosing array keys, you may flatten a multi-dimensional array using a recursive closure as a callback that utilizes array_values(), making sure that this callback is a parameter for array_walk(), as follows.

<?php  

$array = [1,2,3,[5,6,7]];
$nu_array = null;
$callback = function ( $item ) use(&$callback, &$nu_array) {
    if (!is_array($item)) {
    $nu_array[] = $item;
    }
    else
    if ( is_array( $item ) ) {
     foreach( array_values($item) as $v) {
         if ( !(is_array($v))) {
             $nu_array[] = $v;
         }
         else
         { 
             $callback( $v );
         continue;
         }    
     }
    }
};

array_walk($array, $callback);
print_r($nu_array);

The one drawback of the preceding example is that it involves writing far more code than the following solution which uses array_walk_recursive() along with a simplified callback:

<?php  

$array = [1,2,3,[5,6,7]];

$nu_array = [];
array_walk_recursive($array, function ( $item ) use(&$nu_array )
                     {
                         $nu_array[] = $item;
                     }
);
print_r($nu_array);

See live code

This example seems preferable to the previous one, hiding the details about how values are extracted from a multidimensional array. Surely, iteration occurs, but whether it entails recursion or control structure(s), you'll only know from perusing array.c. Since functional programming focuses on input and output rather than the minutiae of obtaining a result, surely one can remain unconcerned about how behind-the-scenes iteration occurs, that is until a perspective employer poses such a question.

Comments

0

You can use the flatten function from Non-standard PHP library (NSPL). It works with arrays and any iterable data structures.

assert([1, 2, 3, 4, 5, 6, 7, 8, 9] === flatten([[1, [2, [3]]], [[[4, 5, 6]]], 7, 8, [9]]));

Comments

0

Simple approach..See it via recursion..

<?php

function flatten_array($simple){
static $outputs=array();
foreach ( $simple as $value)
{
if(is_array($value)){
    flatten_array($value);
}
else{
    $outputs[]=$value;
}

}
return $outputs;
}

$eg=['s'=>['p','n'=>['t']]];
$out=flatten_array($eg);
print_r($out);

?>

2 Comments

Why is using static a potentially bad idea for this task? Unintended data retention. This will certainly catch programmers by surprise if they don't know/expect this behavior. Look at this demonstration.
You have posted a "code-only" answer -- these are low value on StackOverflow because they fail to educate the OP and future researchers. Please take a moment to improve this answer by including how your answer works and why you feel it is a better idea versus the earlier answers.
0

Someone might find this useful, I had a problem flattening array at some dimension, I would call it last dimension so for example, if I have array like:

array (
  'germany' => 
  array (
    'cars' => 
    array (
      'bmw' => 
      array (
        0 => 'm4',
        1 => 'x3',
        2 => 'x8',
      ),
    ),
  ),
  'france' => 
  array (
    'cars' => 
    array (
      'peugeot' => 
      array (
        0 => '206',
        1 => '3008',
        2 => '5008',
      ),
    ),
  ),
)

Or:

array (
  'earth' => 
  array (
    'germany' => 
    array (
      'cars' => 
      array (
        'bmw' => 
        array (
          0 => 'm4',
          1 => 'x3',
          2 => 'x8',
        ),
      ),
    ),
  ),
  'mars' => 
  array (
    'france' => 
    array (
      'cars' => 
      array (
        'peugeot' => 
        array (
          0 => '206',
          1 => '3008',
          2 => '5008',
        ),
      ),
    ),
  ),
)

For both of these arrays when I call method below I get result:

array (
  0 => 
  array (
    0 => 'm4',
    1 => 'x3',
    2 => 'x8',
  ),
  1 => 
  array (
    0 => '206',
    1 => '3008',
    2 => '5008',
  ),
)

So I am flattening to last array dimension which should stay the same, method below could be refactored to actually stop at any kind of level:

function flattenAggregatedArray($aggregatedArray) {
    $final = $lvls = [];
    $counter = 1;
    $lvls[$counter] = $aggregatedArray;


    $elem = current($aggregatedArray);

    while ($elem){
        while(is_array($elem)){
            $counter++;
            $lvls[$counter] = $elem;
            $elem =  current($elem);
        }

        $final[] = $lvls[$counter];
        $elem = next($lvls[--$counter]);
        while ( $elem  == null){
            if (isset($lvls[$counter-1])){
                $elem = next($lvls[--$counter]);
            }
            else{
                return $final;
            }
        }
    }
}

Comments

-1

If you're interested in just the values for one particular key, you might find this approach useful:

function valuelist($array, $array_column) {
    $return = array();
    foreach($array AS $row){
        $return[]=$row[$array_column];
    };
    return $return;
};

Example:

Given $get_role_action=

array(3) {
  [0]=>
  array(2) {
    ["ACTION_CD"]=>
    string(12) "ADD_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [1]=>
  array(2) {
    ["ACTION_CD"]=>
    string(13) "LINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
  [2]=>
  array(2) {
    ["ACTION_CD"]=>
    string(15) "UNLINK_DOCUMENT"
    ["ACTION_REASON"]=>
    NULL
  }
}

than $variables['role_action_list']=valuelist($get_role_action, 'ACTION_CD'); would result in:

$variables["role_action_list"]=>
  array(3) {
    [0]=>
    string(12) "ADD_DOCUMENT"
    [1]=>
    string(13) "LINK_DOCUMENT"
    [2]=>
    string(15) "UNLINK_DOCUMENT"
  }

From there you can perform value look-ups like so:

if( in_array('ADD_DOCUMENT', $variables['role_action_list']) ){
    //do something
};

2 Comments

This is a PHP knock-off of a CFML function by the same name.
I have downvoted because it is the right answer to the wrong question.
-1

any of this didnt work for me ... so had to run it myself. works just fine:

function arrayFlat($arr){
$out = '';
    foreach($arr as $key => $value){

        if(!is_array($value)){
            $out .= $value.',';
        }else{
            $out .= $key.',';
            $out .= arrayFlat($value);
        }

    }
    return trim($out,',');
}


$result = explode(',',arrayFlat($yourArray));
echo '<pre>';
print_r($result);
echo '</pre>';

1 Comment

This code-only answer doesn't work as desired. 3v4l.org/U3bfp <-- proof This is the reason for my downvote.
-1

Given multi-dimensional array and converting it into one-dimensional, can be done by unsetting all values which are having arrays and saving them into first dimension, for example:

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

1 Comment

I have downvoted this answer because it doesn't work on any version. 3v4l.org/7cO9N (Proof) Also, each() is deprecated from php7.2.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.