简体   繁体   中英

Create multidimensional array from flat file array

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
                        (
                        )

                )

        )

)

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"
          }
        }
      }
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM