menu

Questions & Answers

How to create a nested array with dynamic number of nesting levels that is assigned data on creation?

Currently I create the following nested array:

$data = // data from DB
$nested_array = [];
$counter = 0;

foreach ($data as $row) {
    $nested_array[$row->a][$row->b][$row->c]['id'] = $counter++;
}

In the above case I know the amount of nesting levels I want to use, i.e. a,b,c, which are some columns selected from the data

But I want to create the array based on an array of columns that I get. For example if I get:

$columns_selected = ['a', 'b', 'c', 'd', 'e'];

then the nested array should be:

$nested_array[$row->a][$row->b][$row->c][$row->d][$row->e]['id'] = $counter++;
Answers(1) :

evil-ish references in an assigner function could work, something like

function assigner(array &$arr, array $keys, $value = null, bool $onlyFetch = false){
    $target = &$arr;
    foreach($keys as $key){
        $target = &$target[$key];
    }
    $originalValue = $target;
    if(!$onlyFetch){
        $target = $value;
    }
    return $originalValue;
}

now doing

assigner($nested_array, ['a', 'b', 'c', 'd', 'e','id'], "test");

does the same as writing

$nested_array["a"]["b"]["c"]["d"]["e"]["id"] = "test";

3v4l example: https://3v4l.org/#live

Comments:
2023-01-18 23:01:08
thank you! I will try it now. But I think I will need to do some changes because in my case the final nesting level is a string (id), whereas the others are columns from the db ($row->x). I might just edit the function with if condition for the final key or some sort (and pass the $data array)
2023-01-18 23:01:08
@Stackerito could add id to the columns array before giving it to assigner, like assigner($nested_array, [...$columns_selected, "id"], $value); - or you could alter the last line to be $target["id"] = $value; - then your assigner function will only be able to write the "id" property though.
2023-01-18 23:01:08
I will give both a try, but notice that the keys are the column names which I need to access the data they correspond to, so I will also probably need to pass the currently iterated $row from the main foreach so that I can access the data as seen in the question (maybe something like $target = &$target[$row->$key];)
2023-01-18 23:01:08
@Stackerito hmm well the original function didn't return anything, might as well return the original value, and make setting a new value optional. code updated.
2023-01-18 23:01:08
thank you, I edited your answer just to show you what I mean, you don't have to use it, I just wanted to explain it in code. And it's working btw