Flattening a Multidimensional Array

16 10 2014

A 3D projection of an 8-cell performing a doub...

Image via Wikipedia

 

To meet the challenge of flattening a multidimensional array, one should consider whether it matters to preserve the array’s keys. If the keys are unnecessary, you could provide a recursive closure as a callback to array_walk(), as follows:

<?php
$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 = array( 'a',array(1,2), 
                'b',array(3,4, array(5,6, 
                               array('c', array(7,8)))) );
array_walk($array, $callback);
print_r($nu_array);

/**
Array
(
    [0] => a
    [1] => 1
    [2] => 2
    [3] => b
    [4] => 3
    [5] => 4
    [6] => 5
    [7] => 6
    [8] => c
    [9] => 7
    [10] => 8  
)
**/

Notice that the closure is bound to itself and requires the ‘&’ character so that the closure has a reference to itself when it is called recursively. This example has one drawback — a lot of detailed code! Yet, that same code is useful for vividly illustrating what flattening an array involves.

A Walk in the Park

If you wish to write much less code, you may wish to try array_walk_recursive() and again use a closure for a callback.

<?php
$nu_array = null;
$callback = function ( $item ) use(&$nu_array) {
    $nu_array[] = $item;
};
$array = array('apple',
               array(1,2),
              'butter',array(3,4,array(5,array(6,7))));

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

/**
Array
(
    [0] => apple
    [1] => 1
    [2] => 2
    [3] => butter
    [4] => 3
    [5] => 4
    [6] => 5
    [7] => 6
    [8] => 7
)
**/

This solution has several points to recommend it. The concise code is likely faster than the first solution, since the bulk of the work is handled by the faster underlying C source-code of array_walk_recursive(). Also, the closure in this example does not need for the callback to be a bound variable; array_walk_recursive knows where to find it 🙂

SPL Iterators

Peter Cowburn (“salathe”), a notable PHP contributor also explores the issue of flattening a multidimensional array in a blog post. One of his recommendations involves using iterator classes from the SPL library.

This iterators hide even more code which is great if you simply wish for a fast and reliable result. The next example is based on Cowburn’s suggested technique, as follows:

<?php
$array = array(1, array(2,3, array("a","b","c")));

$output = iterator_to_array(new RecursiveIteratorIterator(
    new RecursiveArrayIterator($array)), FALSE);

print_r($output);

/**
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => a
    [4] => b
    [5] => c
)
**/

To grasp this code, start with the array passed to instantiate a RecursiveArrayIterator object. This iterator as its name indicates will traverse a multidimensional array. In this case the iterator gets passed to instantiate a RecursiveIteratorIterator object whose purpose is to iterate over a recursive iterator — how convenient! This object too becomes a parameter along with a mysterious FALSE for interator_to_array(). The function copies the iterated elements into an array. The FALSE parameter indicates that that the array’s keys need not be preserved. If this parameter instead were TRUE, then lost data would result among keys sharing the same name as successive keys would override the preceding ones, as evidenced here.

Additional Sources
http://stackoverflow.com/questions/526556/how-to-flatten-a-multi-dimensional-array-to-simple-one-in-php
http://php.net/manual/en/class.recursivearrayiterator.php
http://php.net/manual/en/class.recursiveiteratoriterator.php
http://php.net/manual/en/function.iterator-to-array.php

This work is licensed under a Creative Commons License

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: