0

I have an array like this:

$arr = array(
    'home.js' => new File(),
    'view/index.html' => new File(),
    'src/index.js' => new File(),
    'src/libs/jquery.js' => new File()
);

Now I want to convert in a structure like this:

Array
(
    [0] => Array
        (
            [text] => home.js
        )

    [1] => Array
        (
            [text] => view
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => index.html
                        )

                )

        )

    [2] => Array
        (
            [text] => src
            [children] => Array
                (
                    [0] => Array
                        (
                            [text] => index.js
                        )

                    [1] => Array
                        (
                            [text] => libs
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [text] => jquery.js
                                        )

                                )

                        )

                )

        )

)

I tried for hours, with help of StackOverfow answers but I couldn't come up with a solution as all other questions have a different setup.


Edit:

What I got so far with the help of SO is (can't remember the exact answer though):

$out = array();
foreach($arr as $path => $file) {
    $parts = explode('/', trim($path, '/'));

    applyChain($out, $parts, $file);
}

function applyChain(&$arr, $parts, $value)
{
    if (!is_array($parts)) {
        return;
    }

    if (count($parts) == 0) {
        $arr = $value;
    } else {
        array_shift($parts);
        applyChain($arr[], $parts, $value);
    }
}

print_r($out);

I don't know how exactly it works, especially the part applyChain($arr[] ...). It kinda works with the depth, but not with the file names. I get following output:

Array
(
    [0] => File Object
        (
        )

    [1] => Array
        (
            [0] => File Object
                (
                )

        )

    [2] => Array
        (
            [0] => File Object
                (
                )

        )

    [3] => Array
        (
            [0] => Array
                (
                    [0] => File Object
                        (
                        )

                )

        )

)
2
  • A recursive function and explode might help. BTW, what have you tried so far? Commented Aug 24, 2015 at 13:04
  • I edited my question with what I tried so far. Commented Aug 24, 2015 at 13:11

1 Answer 1

1

There would be a solution in a few lines using explode() and eval(). But eval() is not considered clean, so lets try recursion:

<?php

class File {
}

$arr = array(
    'home.js' => new File(),
    'view/index.html' => new File(),
    'src/index.js' => new File(),
    'src/libs/jquery.js' => new File()
);

function sub($path) {
        $rv = array();
        $parts = explode('/', $path, 2);           // strip off one level
        $rv['text'] = $parts[0];                   // put it into 'text' element
        if (count($parts)>1)                       // is there anything left?
                $rv['children'] = sub($parts[1]);  // do the same for the rest of the path

        return $rv;
}

$new = array();
foreach (array_keys($arr) as $file) {
        $new[] = sub($file);
}

var_dump($new);

?>

But, as Peter commented, this creates seperate substructures even if the pathes have some part in common (like src/libs/jquery.js and src/libs/melon.js).

With the use of ugly eval() (which can be replaced later) I got the following code:

<?php

class File {
}

$arr = array(
    'home.js' => new File(),
    'view/index.html' => new File(),
    'src/index.js' => new File(),
    'src/libs/jquery.js' => new File(),
    'src/libs/melon.js' => new File(),
);

// conversion
function sub($element) {
        $rv = array();
        foreach (array_keys($element) as $sub) {
                $part['text'] = $sub;
                if (is_array($element[$sub])) {
                        $part['children'] = sub($element[$sub]);
                }
                $rv[] = $part;
        }
        return $rv;
}

// create array with path file/folder names as keys
$new = array();
foreach (array_keys($arr) as $row) {
        $def = '$new["'.preg_replace('&/&', '"]["', $row).'"] = 1;';
        eval($def);
}

// run
$new2 = sub($new);
var_dump($new2);

?>

This outputs

array(3) {
  [0]=>
  array(1) {
    ["text"]=>
    string(7) "home.js"
  }
  [1]=>
  array(2) {
    ["text"]=>
    string(4) "view"
    ["children"]=>
    array(1) {
      [0]=>
      array(1) {
        ["text"]=>
        string(10) "index.html"
      }
    }
  }
  [2]=>
  array(2) {
    ["text"]=>
    string(3) "src"
    ["children"]=>
    array(2) {
      [0]=>
      array(1) {
        ["text"]=>
        string(8) "index.js"
      }
      [1]=>
      array(2) {
        ["text"]=>
        string(4) "libs"
        ["children"]=>
        array(2) {
          [0]=>
          array(1) {
            ["text"]=>
            string(9) "jquery.js"
          }
          [1]=>
          array(1) {
            ["text"]=>
            string(8) "melon.js"
          }
        }
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

7 Comments

Wow, this is great! Thanks for this so far. Do you see an easy solution for multiple files in a folder? Like: 'src/libs/jquery.js' => new File(), 'src/libs/melon.js' => new File(). This would generate a whole new 'root' array. But I would rather have it inside the children array of 'libs'. Anyway, thank you so much for the great start.
I would have generally used the parts as keys, in my opinion the text/children structure is more complicated as it need to be. So you would get: [home.js] => 1, [view] => [index.html] => 1, [src] => [lib] => array([jquery.js] => 1, [melon.js] => 1) (its not really var_dump syntax, but I hope you get what I mean). This could then be output to your structure as well.
I agree with you, that it's more complicated than it needs to be. Unfortunately it's handed to another tool which needs this kind of structure :(
Ok, thank you. eval is not the best solution, but has to do it for now.
Of course, but i had to find a fast and easy solution, because I did not have any more time.
|

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.