1

I'm twisting my brain trying to convert a multi-dimensional associative array into a multi-dimensional non-associative one and got to the point where I decided to seek help..

The whole story:

A. I've got a set of URLs and their KPIs (with an arbitrary folder depth):

URL, Visits

  1. www.example.com
  2. www.example.com/resource1, 100
  3. www.example.com/folderA/resource2, 200
  4. www.example.com/folderA/resource3, 300
  5. www.example.com/folderB/resource4, 400

B. With help of StackOverflow (and surprisingly few lines of PHP -> see here) I was able to transform this into a hierarchical array, representing the URL-structure as folders:

Array
(
[www.example.com] => Array
    (
        [folderA] => Array
            (
                [resource2] => Array
                    (
                        [visits] => 200
                    )

                [resource3] => Array
                    (
                        [visits] => 300
                    )

            )

        [folderB] => Array
            (
                [resource4] => Array
                    (
                        [visits] => 400
                    )

            )

        [resource1] => Array
            (
                [visits] => 100
            )

    )

 )

C. Now, however, I need to get this array into the following structure (children must be non-associative arrays) which is a real brain twister to me...

Array
(
[name] => www.example.com
[isFolder] => 1
[children] => Array
    (
        [0] => Array
            (
                [name] => folderA
                [isFolder] => 1
                [children] => Array
                    (
                        [0] => Array
                            (
                                [name] => resource2
                                [isFolder] => 0
                                [kpis] => Array
                                    (
                                        [visits] => 200
                                    )

                                [children] => Array
                                    (
                                    )

                            )

                        [1] => Array
                            (
                                [name] => resource3
                                [isFolder] => 0
                                [kpis] => Array
                                    (
                                        [visits] => 300
                                    )

                                [children] => Array
                                    (
                                    )

                            )

                    )

            )

        [1] => Array
            (
                [name] => folderB
                [isFolder] => 1
                [children] => Array
                    (
                        [0] => Array
                            (
                                [name] => resource4
                                [isFolder] => 0
                                [kpis] => Array
                                    (
                                        [visits] => 400
                                    )

                                [children] => Array
                                    (
                                    )

                            )

                    )

            )

        [2] => Array
            (
                [name] => resource1
                [isFolder] => 0
                [kpis] => Array
                    (
                        [visits] => 100
                    )

                [children] => Array
                    (
                    )

            )

    )

)

Can anyone help with an approach how to achieve this? Either by transforming the array from step B. or starting from scratch with the original URLs from step A... Any help is greatly appreciated! Thanks a lot!

1 Answer 1

0

Below is a little function that will do just what you want. It uses a reference that is moved through the tree and adds data to the array referenced by that reference where necessary.

I hope the comments give enough explanation of what the code does.

$sourceArray = [
    'www.example.com' => 0,
    'www.example.com/resource1' => 100,
    'www.example.com/folderA/resource2' => 200,
    'www.example.com/folderA/resource3' => 300,
    'www.example.com/folderB/resource4' => 400,
];

function convertToStructure($sourceArray)
{
    // Initialize the tree
    $tree = [
        'name' => 'root',
        'isFolder' => 1,
        'children' => [],
    ];

    // Do nothing if sourceArray is not an array
    if(!is_array($sourceArray)){
        return $tree;
    }

    // Loop through the source array
    foreach($sourceArray as $path => $visits){
        // Get a reference to the target tree
        $treeReference = &$tree;

        // Split the path into pieces
        $path = explode('/', $path);

        // For each piece:
        foreach($path as $key => $name){
            // Get the childKey if the child already exists
            $childKey = findChild($treeReference, $name);

            // Create a new child otherwise
            if ($childKey === false) {
                $treeReference['children'][] = [
                    'name' => $name,
                    'isFolder' => 0,
                    'children' => [],
                ];

                // Get the key of the new child item
                end($treeReference['children']);
                $childKey = key($treeReference['children']);
            }

            // Change the reference to the correct child item.
            $treeReference = &$treeReference['children'][$childKey];

            // Set isFolder if necessary
            $isFolder = ($key == count($path) - 1 ? 0 : 1);
            if(!empty($isFolder)){
                $treeReference['isFolder'] = $isFolder;
            }

            // Set visits if necessary
            if(!empty($visits)){
                $treeReference['isFolder'] = ['kpis' => ['visits' => $visits]];
            }
        }
    }

    return $tree;
}

function findChild($tree, $name)
{
    if(empty($tree['children'])){
        return false;
    }

    foreach($tree['children'] as $key => $child){
        if($child['name'] == $name){
            return $key;
        }
    }
    return false;
}

$treeStructure = convertToStructure($sourceArray);
Sign up to request clarification or add additional context in comments.

1 Comment

Very nice - works like a charm! Thank you very much for that qualified and working example!

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.