Credit to the link posted by fubar, which https://github.com/illuminate/support/blob/master/Arr.php#L514 contains the a "set" function, which will set array elements dynamically at different depths, based on a string input.
e.g. if you have an empty array called $foo
and you call set($foo, "level1.level2", "someValue");
, then $foo
will subsequently look this this (from a call to print_r()):
Array
(
[level1] => Array
(
[level2] => someValue
)
)
Having shamelessly incorporated that incredibly useful function, the solution is then really quite simple:
<?php
$categories = [
'Budget:Necessities' => 0,
'Budget:Necessities:Phone' => 200.00,
'Budget:Necessities:Home' => 0,
'Budget:Necessities:Home:Rent' => 450.00,
'Budget:Savings' => 500,
'Budget:Savings:Vacation' => 300,
];
$output = array();
//loop each array entry. $key will be the string, $val will be the balance
foreach ($categories as $key => $val)
{
$levels = str_replace(":", ".", $key); //replace : with . for compatibility with the set() function
$levels = substr(strstr($levels, '.'), 1); //remove the "Budget" entry
set($output, "$levels.balance", $val); //set a "balance" entry for each item
}
print_r($output); //output using print_r for demonstration, but you can output some other way, as per your needs.
function set(&$array, $key, $value)
{
if (is_null($key)) {
return $array = $value;
}
$keys = explode('.', $key);
while (count($keys) > 1) {
$key = array_shift($keys);
// If the key doesn't exist at this depth, we will just create an empty array
// to hold the next value, allowing us to create the arrays to hold final
// values at the correct depth. Then we'll keep digging into the array.
if (! isset($array[$key]) || ! is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}
?>
Which will get you output as follows:
Array
(
[Necessities] => Array
(
[balance] => 0
[Phone] => Array
(
[balance] => 200
)
[Home] => Array
(
[balance] => 0
[Rent] => Array
(
[balance] => 450
)
)
)
[Savings] => Array
(
[balance] => 500
[Vacation] => Array
(
[balance] => 300
)
)
)
Working demo here: https://eval.in/1045835