0

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]
4
  • Have you tried pluck('children.id')? Not sure if pluck() supports dot syntax. Commented Jan 26, 2021 at 23:53
  • Pluck only returns the first level id. children.pluck returns null Commented Jan 27, 2021 at 0:00
  • 1
    Maybe array_column can help. Commented Jan 27, 2021 at 0:15
  • array_column seems to get the values from an array of arrays. This structure is many levels deep, and so this isn't working Commented Jan 27, 2021 at 0:30

1 Answer 1

1

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

Code execution in Tinker console

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();
Sign up to request clarification or add additional context in comments.

1 Comment

I don't understand it. But it works perfectly. Thanks for your help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.