从平面文件数组创建多维数组

时间:2015-08-24 13:00:17

标签: php multidimensional-array structure flat

我有一个这样的数组:

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

现在我想转换成这样的结构:

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
                                        )

                                )

                        )

                )

        )

)

我在StackOverfow答案的帮助下试了好几个小时,但由于所有其他问题都有不同的设置,我无法提出解决方案。

修改

到目前为止,我在SO的帮助下得到了(虽然不记得确切的答案):

$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);

我不知道它究竟是如何工作的,尤其是部分applyChain($arr[] ...)。它有点适用于深度,但不适用于文件名。我得到以下输出:

Array
(
    [0] => File Object
        (
        )

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

        )

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

        )

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

                )

        )

)

1 个答案:

答案 0 :(得分:1)

使用explode()eval()会在几行中找到解决方案。但eval()不被认为是干净的,所以让我们试试递归:

<?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);

?>

但是,正如Peter所评论的那样,即使这些部分有一些共同点(例如src/libs/jquery.jssrc/libs/melon.js),这也会产生单独的子结构。

使用丑陋的eval()(稍后可以替换)我得到以下代码:

<?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);

?>

此输出

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