user7856768
user7856768

Reputation:

Convert a flat associative array to a multidimensional array by parsing delimited keys as the new key path

I have an array that looks something like this:

array:2 [
    "test1_test2_test3" => "result"
    "category_slug" => "the_slug"
]

What I need to do is convert it to a multidimensional array that would look something like this:

array:2 [
    "test1" => [
        "test2" => [
            "test3" => "result"
        ]
    ]
    "category" => [
        "slug" => "the_slug"
    ]
]

I know that I can explode on the key to get an array but am unsure of how to then go from this to end up with the final result.

EDIT The array looks like that initially because it's being pulled from request parameters: http://url.com?test1.test2.test3=result&category.slug=the_slug and Laravel auto converts it to an array.

Upvotes: 2

Views: 257

Answers (4)

user7856768
user7856768

Reputation:

Looking through the Laravel documentation I found a helper array_set, which means in order to change the key to a multidimensional array I can change the key to use dot notation with str_replace and then use the helper to convert it over:

$array = [
    "test1_test2_test3" => "result"
    "category_slug" => "the_slug"
]

$new_array = []

foreach($array as $key => $value)
{
    $key = str_replace('_', '.', $key);
    array_set($new_array, $key, $value);
}

Result:

array:2 [
    "test1" => [
        "test2" => [
            "test3" => "result"
        ]
    ]
    "category" => [
        "slug" => "the_slug"
    ]
]

Upvotes: 0

Jeto
Jeto

Reputation: 14927

A simple solution:

$result = [];
foreach ($array as $key => $value) {
    foreach (array_reverse(explode('_', $key)) as $key_part) {
        $value = [$key_part => $value];
    }
    $result += $value;
}

If you need to handle several keys with the same parts (such as test1_test2_test3 and test1_test2_test4), replace the last line with:

$result = array_merge_recursive($result, $value);

Upvotes: 1

man0v
man0v

Reputation: 674

One way to go:

$arr = array("test1_test2_test3" => "result", "category_slug" => "the_slug");
$res = array();

foreach($arr as $k=>$v) {

        $t = explode("_", $k);
        $new_arr = array();
        $tmp = $v; 
        for($i=count($t)-1; $i > 0; $i--) {
                $new_arr[$t[$i]] = $tmp;
                $tmp = $new_arr;
                $new_arr = array();
        }

        $res[$t[0]] = $tmp;

}

print_r($res);

Result:

Array
(
    [test1] => Array
        (
            [test2] => Array
                (
                    [test3] => result
                )

        )

    [category] => Array
        (
            [slug] => the_slug
        )

)

Upvotes: 0

Jordi Kroon
Jordi Kroon

Reputation: 2597

My approach would be to reverse the array, then loop through the keys and nest them.

The code below should do the trick.

$array = [
    "test1_test2_test3" => "result",
    "category_slug" => "the_slug"
];

$array = array_map(function ($key, $value) {
    $keys = array_reverse(explode('_', $key));
    while($key = array_shift($keys)) {
        $value = [$key => $value];
    }

    return $value;
}, array_keys($array), $array);

$array = call_user_func_array('array_merge', $array);
var_dump($array);

/**
array(2) {
    ["test1"]=>
    array(1) {
        ["test2"]=>
        array(1) {
            ["test3"]=>
            string(6) "result"
        }
    }
    ["category"]=>
    array(1) {
        ["slug"]=>
        string(8) "the_slug"
    }
}
*/

Upvotes: 0

Related Questions