32

Possible Duplicate:
PHP convert nested array to single array while concatenating keys?
Get array's key recursively and create underscore seperated string

Please, read the whole question before answering.

I have this multidimensional array:

$data = array(
    'user' => array(
        'email'   => '[email protected]',
        'name'    => 'Super User',
        'address' => array(
            'billing' => 'Street 1',
            'delivery' => 'Street 2'
        )
    ),
    'post' => 'Hello, World!'
);

I want it flatten, transformed into:

$data = array(
    'user.email' => '[email protected]',
    'user.name'  => 'Super User',
    'user.address.billing'  => 'Street 1',
    'user.address.delivery' => 'Street 2',
    'post'       => 'Hello, World!'
);

Important:

  • The keys are very important to me. I want them concatenated, separated by periods.

  • It should work with any level of nesting.

Thank you!

3
  • There are several similar questions, but I have not found a duplicate. Commented Mar 3, 2012 at 12:35
  • 1
    Indeed, there are two duplicates. I didn't know when asking. Anyway, all answers to them (except meagar's one) are far inferior than the ones given here now... they are unnecessarily complicated (using iterators, globals, classes, and the like, when it can be as simple as we can see here). Commented Mar 3, 2012 at 13:19
  • For those developing with Laravel, just enjoy its in-built methods. See Convert a multidimensional collection (array) to a flattened structure with dot-delimited keys in Laravel Commented May 4, 2024 at 22:23

5 Answers 5

76

Something like this should work:

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

DEMO

Sign up to request clarification or add additional context in comments.

2 Comments

thank you! you also have the counterpart? create a multi-array from this flatten array?
you sir, thank you, shame it is the last answer in the order, almost did not notice it
25

Thanks for all the given answers.

I have transformed it in the following, which is an improved version. It eliminates the need of a root prefix, does not need to use references, it is cleaner to read, and it has a better name:

function array_flat($array, $prefix = '')
{
    $result = array();

    foreach ($array as $key => $value)
    {
        $new_key = $prefix . (empty($prefix) ? '' : '.') . $key;

        if (is_array($value))
        {
            $result = array_merge($result, array_flat($value, $new_key));
        }
        else
        {
            $result[$new_key] = $value;
        }
    }

    return $result;
}

1 Comment

Works like a treat. Though if any child arrays use numeric keys, the function will still add the numeric key as the prefix, like user.2. To avoid this, I've just added a simple condition below the $new_key line to check if it is numeric to simply use the previous prefix. if ( is_numeric( $key ) ) { $new_key = $prefix; }
9

Try this

<?php

$data = array(
    'user' => array(
        'email'   => '[email protected]',
        'name'    => 'Super User',
        'address' => array(
            'billing' => 'Street 1',
            'delivery' => 'Street 2'
        )
    ),
    'post' => 'Hello, World!'
);

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

var_dump(prefixKey('', $data));

?>

Outputs

array
  'user.email' => string '[email protected]' (length=16)
  'user.name' => string 'Super User' (length=10)
  'user.address.billing' => string 'Street 1' (length=8)
  'user.address.delivery' => string 'Street 2' (length=8)
  'post' => string 'Hello, World!' (length=13)

6 Comments

Really cool, and helpful. Thanks! I will suggest an edit (I removed the need of setting a root prefix).
Hmmm, as I couldn't, I will post as a separated answer.
+1 - Led me to the right path. I'd accepted it if didn't require a root prefix.
changed it a bit so it won't do an initial prefix.
ah nevermind. it's nearly the same as Felix Kling's solution.
|
3

test this out here

i passed by reference so no need for returns. just hand over the array storage.

$store = array();

function flatten($array,&$storage,$parentKey = ''){
    foreach($array as $key => $value){
    $itemKey = (($parentKey)? $parentKey.'.':'').$key;
        if(is_array($value)){
            flatten($value,$storage,$itemKey);
        } else {
            $storage[$itemKey] = $value;
        }
    }   
}

flatten($data,$store);
var_dump($store);

Comments

1

Use recursion such as this:

function process_data( $data, $parent_key ){

    if ( ! is_array( $data ) ){
        return $data;
    }

    $flattened_array = array();
    foreach( $data as $key => $item ){
        $flattened_key = $parent_key . '.' . $key;
        $flattened_array[ $flattened_key ] = process_data( $item, $flattened_key );
    }

    return $flattened_array;

}

2 Comments

Cool. +1 But I don't want to specify a root key.
$flattened_key = ( empty( $parent_key ) ) ? $key : $parent_key . '.' . $key;

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.