Создать многомерный массив из плоского файлового массива

У меня есть такой массив:

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

)

)

)

0

Решение

Там будет решение в несколько строк, используя 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);

?>

Но, как прокомментировал Питер, это создает отдельные подструктуры, даже если пути имеют некоторую общую часть (например, src/libs/jquery.js а также src/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"}
}
}
}
}
}
1

Другие решения

Других решений пока нет …