I need to generate a multidimensional array based on a "map" of letters
my array :
$list = [
0 => [
'name' => 'blah',
'path' => 'A'
],
1 => [
'name' => 'blah',
'path' => 'AA'
],
2 => [
'name' => 'blah',
'path' => 'AB'
],
3 => [
'name' => 'blah',
'path' => 'B'
],
4 => [
'name' => 'blah',
'path' => 'BA'
],
5 => [
'name' => 'blah',
'path' => 'BAA'
],
];
but I need this:
$list = [
0 => [
'name' => 'blah',
'path' => 'A',
'childs' => [
0 => [
'name' => 'blah',
'path' => 'AA'
],
1 => [
'name' => 'blah',
'path' => 'AB'
],
]
],
3 => [
'name' => 'blah',
'path' => 'B',
'childs' => [
0 => [
'name' => 'blah',
'path' => 'BA',
'childs' => [
0 => [
'name' => 'blah',
'path' => 'BAA'
],
]
],
]
],
];
I’m going to need this array to be in a way that is easy to manipulate, but I’m not able to use the "&" in a foreach so that I can generate an array at least close to what I put above.
sorry if i asked the question incorrectly… my english is bad and it’s my first time here
5
Answers
my solution:
Because there weren’t much clues on the question on how to actually do the desired grouping. I’ll assume, based on the provided output sample, that the grouping will be based on the first letter found in the values where the key is
path
. The task will basically be solved usingarray_reduce()
built-in function:To maintain a performant solution, we’ll index the resulting array based on the letters we found (the letters we’ll group using them). Like so we will iterate over the
$list
array only once.The trick here is to decide what to do at every iteration of the
array_reduce
function:$letter
, then we will construct an array (based on your output sample) where$letter
is the key.children
of the resulting array of the$letter
key.Using the letters as keys will drastically improve the solution’s performance because we can simply say
$result[$letter]
and this will immediately return the array found on the$letter
key (O(1)).To illustrate, here’s a code sample that should get the job done:
The
$result
array will have the letters as keys, if you need to remove those letters and use numerical keys, you may callAnd I have made a live demo too.
I would loop through the
$list
giving each item a['childs']
array then copy into a$new_list
based on the path using the letters as keys in the array. I accomplish this below by constructing a string to evaluate witheval()
.The above code outputs the following:
See it in action here: https://onlinephp.io/c/cf8d0
Note:
This works because you have all ancestor-items defined in
$list
before their descendants. If the order of items varies (like'AAB'
before'AA'
) then you will need to add some checks to see if the$new_list['A']['childs']['A']['childs']
array exists yet and construct it when necessary.This recursive approach seeks out qualifying rows, pushes them as children of the desired parent row and unsets all rows that are used as children of a parent (somewhere). The new array structure is not returned; the input array is modified by reference.
Code: (Demo)
Here is a non-recursive approach that does provides the result in a new variable by sorting the array with deepest children first then using a nested loop to brute-force search for parents.
Code: (Demo)