Reputation: 2245
I have a multidimensional Laravel collection of pages for a navigation menu.
{
id: 1,
...
children: [
{
id: 2,
...
children: [
{
id: 3,
...
children: []
}
]
},
{
id: 4,
...
children: []
}
]
}
The collection has no limit on its depth or the amount of siblings for each tier. However, there is only one page at the root level. i.e. the first page (id 1) has no siblings. How can I extract all the ids into a single array?
expected output
[1,2,3,4]
Upvotes: 0
Views: 1785
Reputation: 15786
I got the result you want with the following test object.
$object = [
(object)['id' => 1, 'children' => []],
(object)['id' => 2, 'children' => [
(object)['id' => 4, 'children' => [
(object)['id' => 6, 'children' => []]
],
(object)['id' => 5, 'children' => []]
],
(object)['id' => 3, 'children' => []]
]
=> [
{#4565
+"id": 1,
+"children": [],
},
{#4605
+"id": 2,
+"children": [
{#4567
+"id": 4,
+"children": [
{#4563
+"id": 6,
+"children": [],
},
],
},
{#4564
+"id": 5,
+"children": [],
},
],
},
{#4551
+"id": 3,
+"children": [],
},
]
To manage it, I had to use some recursion. I am not sure it's the best but it gets the job done.
function getIds($item) {
return [$item->id, collect($item->children)->map('getIds')->all()];
}
$ids = collect($object)
->map('getIds') // call getIds function which will in turn do the same for all children
->flatten() // flatten the resulting array
->sort() // sort the resulting ids since they probably won't be in order
->values() // only interested in the values, not the keys
->all(); // transform collection to array
EDIT: Found a way to further inlne this.
$ids = collect($object)
->map($closure = function($item) use (&$closure) {
return [$item->id, collect($item->children)->map($closure)->all()];
})
->flatten()
->sort()
->values()
->all();
Upvotes: 1