Thursday, 30 August 2018

PHP transforms an associative array from string to tree

I have a list of path (just strings), like this:

$data = array(
    array('path' => 'foo/bar/baz'),
    array('path' => 'foo/bar/baz/qux'),
    array('path' => 'foo/bar'),
    array('path' => 'bar/baz/foo'),
    array('path' => 'baz'),
);

I would like to achieve a structure like this
Array
(
    [foo] => Array
        (
            [bar] => Array
                (
                    [baz] => Array
                        (
                            [qux] => null
                        )
                )
        )
    [bar] => Array
        (
            [baz] => Array
                (
                    [foo] => null
                )
        )
    [baz] => null
)

Side note
  1. the structure displays only, non-common portions
  2. the leaf would be null (null for me would be without children)
I know you will ask me what have you tried? the problem is: I don't know how to deal the problem in the right way
can you give me some advice, without massacre of downvote?

I got pretty close, but instead of the endings being null, they're array's with size 0.
<?php

function ProcessPath($entry,$depth,&$current)
{
  if($depth<count($entry))
  {
    $key = $entry[$depth];
    if(!isset($current[$key]))$current[$key] = null;
    ProcessPath($entry,$depth+1,$current[$key]);
  }
}

$data = array(
  array('path' => 'foo/bar/baz'),
  array('path' => 'foo/bar/baz/qux'),
  array('path' => 'foo/bar'),
  array('path' => 'bar/baz/foo'),
  array('path' => 'baz'),
);
$result = null;
foreach($data as $path)
{
  ProcessPath(explode("/",$path['path']),0,$result);
}

print_r($result);

?>

output
Array
(
    [foo] => Array
        (
            [bar] => Array
                (
                    [baz] => Array
                        (
                            [qux] =>
                        )

                )

        )

    [bar] => Array
        (
            [baz] => Array
                (
                    [foo] =>
                )

        )

    [baz] =>
)

Essentially the function ProcessPath takes:
  • An array of the split path
  • The current depth eg: [foo] (0) or foo > [bar] (1) or foo > bar > [baz] (2)
  • A reference to where on the array the path is being put (denoted by &$reference
First off the function checks if the depth is within the current path being processed.
Then it extracts the $key to simplify the rest of the code.
This is where the magic happens, if the output hasn't got the current path segment set, it sets it.
The last line recurses onto the next element in the path $entry by taking the same $entry, increasing the $depth by 1, and changing the $current to the new section $current[$key].

0 comments:

Post a Comment