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
CodePudding user response:
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 using array_reduce()
built-in function:
Iteratively reduce the array to a single value using a callback function. Source: php.net
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:
- When it's the first time we encounter a new letter, let's call that letter
$letter
, then we will construct an array (based on your output sample) where$letter
is the key. - Otherwise, if we have already the letter in the resulting array we will simply merge the
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:
$list = [
['name' => 'blah', 'path' => 'A'],
['name' => 'blah', 'path' => 'AA'],
['name' => 'blah', 'path' => 'AB'],
['name' => 'blah', 'path' => 'B'],
['name' => 'blah', 'path' => 'BA'],
['name' => 'blah', 'path' => 'BAA'],
];
$result = array_reduce($list, function ($a, $c) {
$l = substr($c['path'], 0, 1);
isset($a[$l])
? $a[$l]['children'][] = $c
: $a[$l] = [
'name' => $c['name'],
'path' => $c['path'],
'children' => []
];
return $a;
}, []);
The $result
array will have the letters as keys, if you need to remove those letters and use numerical keys, you may call
And I have made a live demo too.