【问题标题】:Create multidimensional array from flat file array从平面文件数组创建多维数组
【发布时间】:2015-08-24 13:00:16
【问题描述】:

我有一个这样的数组:

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

                )

        )

)

【问题讨论】:

  • 递归函数和爆炸可能会有所帮助。顺便说一句,到目前为止你尝试过什么?
  • 我用迄今为止的尝试编辑了我的问题。

标签: php multidimensional-array structure flat


【解决方案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"
          }
        }
      }
    }
  }
}

【讨论】:

  • 哇,太棒了!到目前为止,谢谢。您是否看到一个文件夹中多个文件的简单解决方案?喜欢:'src/libs/jquery.js' =&gt; new File(), 'src/libs/melon.js' =&gt; new File()。这将生成一个全新的“根”数组。但我宁愿将它放在“libs”的子数组中。无论如何,非常感谢您的良好开端。
  • 我通常会使用部分作为键,在我看来,文本/子结构更复杂,因为它需要。所以你会得到:[home.js] =&gt; 1, [view] =&gt; [index.html] =&gt; 1, [src] =&gt; [lib] =&gt; array([jquery.js] =&gt; 1, [melon.js] =&gt; 1)(它不是真正的 var_dump 语法,但我希望你明白我的意思)。然后也可以将其输出到您的结构中。
  • 我同意你的观点,它比它需要的更复杂。不幸的是,它被交给了另一个需要这种结构的工具:(
  • 好的,谢谢。 eval 不是最好的解决方案,但现在必须这样做。
  • 当然可以,但是我必须找到一个快速简便的解决方案,因为我没有更多时间了。
猜你喜欢
  • 2017-12-11
  • 1970-01-01
  • 1970-01-01
  • 2014-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多