Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP convert nested array to single array while concatenating keys?

Here is an example array:

 $foo = array(
           'employer' => array(
                    'name' => 'Foobar Inc',
                    'phone' => '555-555-5555'
                     ),
           'employee' => array(
                    'name' => 'John Doe',
                    'phone' => '555-555-5556',
                    'address' => array(
                           'state' => 'California',
                           'zip' => '90210'
                        )
                    ),
           'modified' => '2009-12-01',
         );

And I would like to get a result like this:

$fooCompressed = array(
             'employer_name' => 'Foobar Inc',
             'employer_phone' => '555-555-5555',
             'employee_name' => 'John Doe',
             'employee_phone' => '555-555-5556'
             'employee_address_state' => 'California',
             'employee_address_zip' => '90210',
             'modified' => '2009-12-01'
             )

How would I go about writing a recursive function to handle this?

like image 302
GSto Avatar asked Dec 10 '09 18:12

GSto


1 Answers

Approach I liked more is quite similar to some posted here but not equal. I found it into a duped post: https://stackoverflow.com/a/9546215/4791386 by user "Felix Kling"

His code flattens array keys resulting single dimension array with dot concatenated keys, which implies that numerical arrays will creates his own "key paths". This is very useful, but in large amount of similar items inside array could result a ton of meaningless similar paths.

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

In my case, I also needed a "unique like" path flattening as array key, and a sample of the data I could spec. So I extend his approach adding a numeric key squashing optional parameter. Also added optional parameter separator configuration.

The main purpose is make easy to analyze key structure and path related data. I think this method is useful when intended task is key mapping for further full data operations.

/**
* Convert a multidimensional array into a single dimension array.
* Nested array keys will be concatenated with the $separator string
* Numeric keys can also be flattened in a "unique key" array style with $numeric_squash 
* If $numeric_squash is true, numeric array keys are concatenated with $numeric_squash_separator, 
* for later detection and processing if necessary. "[*]" by default.
* If $numeric_squash_separator is set to false, the array key is flattened so that the values 
* would be displayed as if there were no numeric array.
*
* array  $array                    : Array to be flattened
* string $prefix                   : String to prepend on flattened keys
* string $separator                : String concatenated between nested array keys.
* bool   $numeric_squash           : Squash numeric array keys
* string $numeric_squash_separator : String replacing numeric keys, none if false

*/  

public static function array_flatten($array, $prefix = '', $separator = '.' , $numeric_squash = false , $numeric_squash_separator = '[*]') {
    $result = array();
    foreach($array as $key => $value) {
        if(is_array($value)) {
            if($numeric_squash && is_numeric($key))
                $n_key = $numeric_squash_separator ? $numeric_squash_separator . $separator: '';
            else
                $n_key = $key . $separator;

            $result = $result + self::array_flatten($value, $prefix . $n_key  , $separator , $numeric_squash , $numeric_squash_separator);
        }
        else {
            $result[$prefix . ($numeric_squash && is_numeric($key) ? '' : $key)] = $value;
        }
    }
    return $result;
}

Also say that this function is not performance optimized, iterations can be saved on numeric_squash and also some compare operations I think.

like image 119
Diego Martínez Avatar answered Nov 06 '22 08:11

Diego Martínez