Max Rosenbaum

Max Rosenbaum

Software developer

Thursday, 8 April 2021

Flatten multi-dimensional array in PHP 7

It's not too often in the PHP world you'll need to flatten arrays. When you do, map operations and array functions are a bit clunky. I had a look for a solution on stackoverflow and the answers didn't have quite what I was after. After diving headlong into the documentation, here are two solutions for flattening a multi-dimensional array in PHP 7.

Only one level, no key preservation

If the source array you are working with is only one level deep, (an array of arrays) a simple way to merge them together without key preservation is using the array_merge and the splat operator in PHP 7;

array_merge(...$multiDimensionalArray)

Multilevel, with key preservation

Below is a recursive implementation for supporting arrays of any depth and retaining the keys of the values. PHP won't optimise for tail recursion, so in very large arrays you might get a stackoverflow.

A big weakness of array in PHP is not having a native way to handle duplicate keys in its internal data structures. In this solution we drop a key if we find a duplicate. Alternatively it would be possible to append a random string onto the end of a key, but if data is encoded into the keys this would get very messy very fast. Unfortunately there is no good way to handle this problem in a pure flatmap solution.

Here it is in action on 3v4l.

$testArray = [
  ['lev 1' => 'lev 1'],
  ['lev 2', 'lev 2 - 1', ['lev 2 - 2'], ['Key preserved' => 'lev 2 - 3']],
  [['lev 3 - 1', 'lev 3 - 2', 'lev 3 - 3']],
  [[[888 => 'lev 4']]]
];

// $element must initially be an array. Anything that is not an array will just return the accumulator.
function flatten($element, $accum = []) {

  // If we don't have an array, return the accumulator.
  if (!is_array($element)) {
     return $accum;
  }
  
  foreach($element as $key => $e) {
    // Check if the elements are an array or not. If not, append the accumulator with a key and value.
    if (!is_array($e)) {
      // Check that the key does not already exist, if it does we have to simply append to preserve values.
      if (array_key_exists($key, $accum)) {
        $accum[] = $e;
      } else {
        $accum[$key] = $e;
      }
      continue;
    }
    
    // Only recurse when we have an array.
    // We pass in the accumulator and any values further down then hierarchy.
    $vals = flatten($e, $accum);
    
    // We might get an empty array back if there was an array of arrays.
    if (!empty($vals)) {
      // We don't append our values here, we override the accumulator. The appending happens above when $e is not an
      // array.k
      $accum = $vals;
    }
  }
  
  // Return values of this array and all child arrays.  
  return $accum;
}

flatten($testArray);
picture of the author
Tuesday, 30 November 2021

Plugin architecture

The Swiss army knife of architectures

medium software-architecture python

Continue reading >>