29

There are plenty of tips and code examples out there of accessing PHP arrays with dot notation, but I would like to do somewhat the opposite. I would like to take a multidimensional array like this:

$myArray = array(
 'key1' => 'value1',
 'key2' => array(
 'subkey' => 'subkeyval'
 ),
 'key3' => 'value3',
 'key4' => array(
 'subkey4' => array(
 'subsubkey4' => 'subsubkeyval4',
 'subsubkey5' => 'subsubkeyval5',
 ),
 'subkey5' => 'subkeyval5'
 )
);

And turn it into this (likely through some recursive function):

$newArray = array(
 'key1' => 'value1',
 'key2.subkey' => 'subkeyval',
 'key3' => 'value3',
 'key4.subkey4.subsubkey4' => 'subsubkeyval4',
 'key4.subkey5.subsubkey5' => 'subsubkeyval5',
 'key4.subkey5' => 'subkeyval5'
);
asked May 3, 2012 at 2:31
2
  • I thought array_walk_recursive might be able to help me to build the new keys since it seemed like it could do a lot of the heavy lifting with recursion but it doesn't provide all the keys of the array. For instance, using array_walk_recursive on $myArray (as run through the example function on the PHP documentation page) would only provide me with the keys that don't have array values. I'm continuing to attempt writing my own recursive function with some good old foreach looping but it's been a long day and is hurting my head. I'll continue to go at it and update if I get it (or any closer) Commented May 3, 2012 at 2:58
  • 3
    Laravel has Illuminate\Support\Arr::dot($the_array) to do it, it can be tested in php artisan tinker. Commented Mar 23, 2021 at 10:40

5 Answers 5

89

teh codez

$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
$result = array();
foreach ($ritit as $leafValue) {
 $keys = array();
 foreach (range(0, $ritit->getDepth()) as $depth) {
 $keys[] = $ritit->getSubIterator($depth)->key();
 }
 $result[ join('.', $keys) ] = $leafValue;
}

output

Array
(
 [key1] => value1
 [key2.subkey] => subkeyval
 [key3] => value3
 [key4.subkey4.subsubkey4] => subsubkeyval4
 [key4.subkey4.subsubkey5] => subsubkeyval5
 [key4.subkey5] => subkeyval5
)

demo: http://codepad.org/YiygqxTM

I need to go, but if you need an explanation of that tomorrow, ask me.

answered May 3, 2012 at 2:57
Sign up to request clarification or add additional context in comments.

3 Comments

Now, how about the reverse of this function?
@Petah, see stackoverflow.com/q/9635968/1388892 @ rambocoder, what is a "ritit"? I mean the word... thx! --> ah, RecursiveITeratorITerator... righty right :)
I love this. Built a custom function before I saw this. This is slightly slower but nicely handles index-less arrays/sub-arrays. Nice one!
7

There is already the answer with RecursiveIteratorIterator. But here is a more optimal solution, that avoids using nested loops:

$iterator = new RecursiveIteratorIterator(
 new RecursiveArrayIterator($arr),
 RecursiveIteratorIterator::SELF_FIRST
);
$path = [];
$flatArray = [];
foreach ($iterator as $key => $value) {
 $path[$iterator->getDepth()] = $key;
 if (!is_array($value)) {
 $flatArray[
 implode('.', array_slice($path, 0, $iterator->getDepth() + 1))
 ] = $value;
 }
}

There are several points need to be made here. Notice the use of RecursiveIteratorIterator::SELF_FIRST constant here. It is important as the default one is RecursiveIteratorIterator::LEAVES_ONLY which wouldn't let us access all keys. So with this constant set, we start from the top level of an array and go deeper. This approach lets us store the history of keys and prepare the key when we rich leaf using RecursiveIteratorIterator::getDepth method.

Here is a working demo.

answered Oct 24, 2016 at 11:37

Comments

6

This will handle an arbitrary level of nesting:

<? //PHP 5.4+
$dotFlatten = static function(array $item, $context = '') use (&$dotFlatten){
 $retval = [];
 foreach($item as $key => $value){
 if (\is_array($value) === true){
 foreach($dotFlatten($value, "$context$key.") as $iKey => $iValue){
 $retval[$iKey] = $iValue;
 }
 } else {
 $retval["$context$key"] = $value;
 }
 }
 return $retval;
};
var_dump(
 $dotFlatten(
 [
 'key1' => 'value1',
 'key2' => [
 'subkey' => 'subkeyval',
 ],
 'key3' => 'value3',
 'key4' => [
 'subkey4' => [
 'subsubkey4' => 'subsubkeyval4',
 'subsubkey5' => 'subsubkeyval5',
 ],
 'subkey5' => 'subkeyval5',
 ],
 ]
 )
);
?>
user2357112
286k32 gold badges491 silver badges571 bronze badges
answered May 3, 2012 at 3:11

1 Comment

This anwser contains the highest performing code. Without array_merge in a loop and using slow SPL.
2

This is my take on a recursive solution, which works for arrays of any depth:

function convertArray($arr, $narr = array(), $nkey = '') {
 foreach ($arr as $key => $value) {
 if (is_array($value)) {
 $narr = array_merge($narr, convertArray($value, $narr, $nkey . $key . '.'));
 } else {
 $narr[$nkey . $key] = $value;
 }
 }
 return $narr;
}

Which can be called as $newArray = convertArray($myArray).

answered May 3, 2012 at 3:19

Comments

1

This another approach similar to Blafrat above - but handles simply arrays as values.

 function dot_flatten($input_arr, $return_arr = array(), $prev_key = '')
 {
 foreach ($input_arr as $key => $value)
 {
 $new_key = $prev_key . $key;
 // check if it's associative array 99% good
 if (is_array($value) && key($value) !==0 && key($value) !==null)
 {
 $return_arr = array_merge($return_arr, dot_flatten($value, $return_arr, $new_key . '.'));
 }
 else
 {
 $return_arr[$new_key] = $value;
 }
 }
 return $return_arr;
}

(The only case this wouldn't catch is where you had a value that was associative but the first key was 0.)

Note that the RecursiveIteratorIterator can be slower than regular recursive function. https://xenforo.com/community/threads/php-spl-why-is-recursiveiteratoriterator-100x-slower-than-recursive-search.57572/

In this case using the sample array given for 1000 iterations php5.6, this code is twice as fast (recursive=.032 vs interator=.062) - but the difference is probably insignificant for most cases. Mainly I prefer recursive because I find the logic of the Iterator needlessly complicated for a simple use case like this.

answered Apr 27, 2015 at 9:32

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.