用PHP动态构建多维数组?

时间:2021-12-02 01:22:25

I have data contained in an array which is like so,

我有一个数组中包含的数据,

$file['info']['files'] = array(
    [0] => array(
         'length' => (int),
         'path' => array (
              [0] => 'file.txt',
         ),
    ),
    [1] => array(
         'length' => (int),
         'path' => array (
              [0] => 'directory one',
              [1] => 'file2.txt',
         ),
    ),
    [2] => array(
         'length' => (int),
         'path' => array (
              [0] => 'directory one',
              [1] => 'directory two',
              [2] => 'file3.txt',
         ),
    ),
);

The $file['info']['files'] array can contain any number of elements. The path array contained in each $file['info']['files'] array is where I am having trouble.

$file['info']['files']数组可以包含任意数量的元素。每个$file['info']['files']数组中包含的路径数组是我遇到麻烦的地方。

It contains information about a file structure. If just 1 element exists then it is a file. If more than one element exists then each element starting from the top is a parent folder of the next element and the last element is the file in the last folder. Taking the example above would be a file structure of

它包含关于文件结构的信息。如果只有一个元素存在,那么它就是一个文件。如果存在多个元素,则从顶部开始的每个元素都是下一个元素的父文件夹,最后一个元素是最后一个文件夹中的文件。以上面的示例为例,文件结构为

FILE file1.txt
FOLDER directory one
     FILE file2.txt
     FOLDER directory two
          FILE {file3.txt}

I would like to extract this data into my own array structure which is to be as follows,

我想把这些数据提取到我自己的数组结构中如下,

 $sortedFiles = array(
     'file1.txt' => (int),
     'directory one' => array(
         'file2.txt' => (int),
         'directory two' => array(
              'file3.txt' => (int),
         ),
     ),
 );

I have this code so far,

我有这个代码,

foreach($file['info']['files'] as $file) {
    // LENGTH AND PATH ARE SET
    if(isset($file['length'], $file['path'])) {
        // GET COUNT OF FILE PATH ARRAY
        $count = count($file['path']);
        // SINGLE FILE
        if($count == 1) {
            $sortedFiles[$file['path'][0]] = $file['length'];
        // FILES IN DIRECTORY
        } else {
            // BUILD ARRAY STRUCTURE FOR DIRECTORIES
        }
    }
}

I am having trouble when it comes to adding directories to the array. I could do it manually and only go so many directories down each time checking if the array for the directory exists and if not create it, and if it does exist then add to it. I tried this with the code below but it only goes one directory deep (the code went where it says // BUILD ARRAY STRUCTURE above).

在向数组中添加目录时,我遇到了麻烦。我可以手动操作,每次只检查目录的数组是否存在,如果不创建,如果存在,就添加到其中。我对下面的代码进行了尝试,但它只深入到一个目录(代码位于上面的// BUILD ARRAY结构)。

// FOLDER NOT SET
if(!isset($files[$file['path'][0]])) {
    $sortedFiles[$file['path'][0]] = array($file['path'][1] => $file['length'],);
// FOLDER SET
} else {
    $sortedFiles[$file['path'][0]][$file['path'][1]] = $file['length'];
}

How can I dynamically create arrays for each directory that exists and add the information that is needed bearing in mind that the directory structure could be any amount of levels deep?

如何动态地为存在的每个目录创建数组,并添加所需的信息,要记住目录结构可以是任何层次的深度?

Thanks for taking the time to read my rather long question and I appreciate any help that anyone gives to me.

感谢您花时间阅读我的长篇大论,我感激任何人给予我的帮助。

4 个解决方案

#1


3  

You will need to call your function recursively, as in the example below:

您将需要递归调用函数,如下面的示例所示:

function get_contents_dir( $dir )
{
    $names = array();

    if ( is_dir($dir) && is_readable($dir) )
    {
            foreach ( scandir($dir) as $file )
            {
                    if ( is_dir($dir."/".$file) && is_readable($dir."/".$file) )
                    {
                            $names[] = get_contents_dir($dir."/".$file);
                    }

                    if ( is_file($dir."/".$file) && is_readable($dir."/".$file) )
                    {
                            $names[] = $dir."/".$file;
                    }
            }
    }

    return $names;
}

This function first opens the set $dir folder and scans the list of files, adding each found file to the array which is, after scanning the folder, returned as the return value of the function.

该函数首先打开set $dir文件夹并扫描文件列表,将找到的每个文件添加到数组中,该数组在扫描文件夹后作为函数的返回值返回。

The twist comes in when an entry of the scandir() result (list of files and folders in the folder) is actually a folder. If that happens, the function is called from it's internals, recursively (see the line $names[] = get_contents_dir($dir."/".$file); calling the function from within the function) and the subfolder will be indexed too. Rinse and repeat, until all subfolders are indexed.

当scandir()结果(文件夹中的文件和文件夹列表)的条目实际上是一个文件夹时,就会出现扭曲。如果发生这种情况,函数将从其内部调用(请参见行$names[] = get_contents_dir($dir."/".$file);从函数中调用函数)和子文件夹也将被索引。冲洗并重复,直到所有子文件夹都被索引。

If you call the function and let it execute, an array will be returned. Each key of the array will be an entry. If it was a file, the value linked to the key is the name of the file, if it was a folder, the value will be another array nested into the previous one.

如果您调用函数并让它执行,将返回一个数组。数组的每个键都是一个条目。如果它是一个文件,那么链接到键的值就是文件的名称,如果它是一个文件夹,那么这个值将是嵌套在前一个文件夹中的另一个数组。

Here is an example dump taken of the returned array:

下面是返回数组的一个示例转储:

array (
  0 => './libmysqlclient.so.16.0.0',
  1 => './libmysqlclient_r.so.16.0.0',
  2 => 
  array (
    0 => './libs/libboost_thread-mt.a',
    1 => './libs/libboost_thread-mt.so.1.38.0',
    2 => './libs/libmysql.dll',
    3 => './libs/libmysqlclient16_5.1.41-3ubuntu12_i386.deb',
  ),
  3 => 
  array (
    0 => './radio_sneaker/cl_auto.lua',
    1 => './radio_sneaker/sh_auto.lua',
    2 => './radio_sneaker/sh_coms.lua',
    3 => './radio_sneaker/sh_info.lua',
    4 => './radio_sneaker/sv_auto.lua',
    5 => './radio_sneaker/sv_hooks.lua',
  ),
  4 => './sv_auto.lua',
)

Compare this output against the tree command ran on the same folder:

将此输出与在同一文件夹中运行的树命令进行比较:

|   libmysqlclient.so.16.0.0
|   libmysqlclient_r.so.16.0.0
|   sv_auto.lua
|   
+---libs
|       libboost_thread-mt.a
|       libboost_thread-mt.so.1.38.0
|       libmysql.dll
|       libmysqlclient16_5.1.41-3ubuntu12_i386.deb
|       
\---radio_sneaker
        cl_auto.lua
        sh_auto.lua
        sh_coms.lua
        sh_info.lua
        sv_auto.lua
        sv_hooks.lua

#2


1  

Why don't you use a join function in php to merge the path to check whether it then exists? If it doesn't then go level by level checking if the folder exists and if it doesn't then create in and move further. My point is that creating such a dynamic structure is, first of all, difficult and easy to mess up. Why not to go the easy way?

为什么不使用php中的join函数合并路径以检查它是否存在?如果该文件夹不存在,则按级别检查该文件夹是否存在,如果该文件夹不存在,则创建并进一步移动。我的观点是,创造这样一个动态的结构,首先,是困难和容易搞砸。为什么不走捷径呢?

#3


1  

Imagine that you have an array representing the directory stucture which is initially empty and will be filled in piece by piece. You need to keep track of a "current" item in this array and iterate over the directory names. At each iteration you would create a sub-array under the current item if it does not already exist and then set the current to be this sub-array.

假设您有一个表示目录结构的数组,该结构最初是空的,并将被逐块填充。您需要跟踪这个数组中的“当前”项并遍历目录名。在每次迭代中,如果当前项不存在,您将在当前项下创建一个子数组,然后将当前数组设置为该子数组。

This can be done either with recursion or with iteration, and since it's PHP the "current" marker would need to be a reference.

这可以用递归或迭代来完成,因为它是PHP,所以“当前”标记需要作为参考。

With this overview in mind, have a look at this question and the answers there. The input there is in the form of a string, but that's just an implode away from your current situation.

带着这个概述,看看这个问题和答案。这里的输入是以字符串的形式出现的,但这只是与当前情况的内爆。

#4


1  

I'll let you wrestle this into your code, but heres the important lessons.

我将让您在代码中处理这个问题,但这里有重要的教训。

turn the flat array into a nested structure

将平面数组转换为嵌套结构

$a = array(
    'dir1', 'dir2', 'file.txt'
);

$structure = array(array_pop($a));
foreach (array_reverse($a) as $dir) {
    $structure = array($dir => $structure);
}

print_r($structure);

merge one structure into another

将一个结构合并到另一个结构中。

$result = array_merge_recursive($result, $structure);

Just iterate over all structures for the merging.

只需遍历合并的所有结构。

#1


3  

You will need to call your function recursively, as in the example below:

您将需要递归调用函数,如下面的示例所示:

function get_contents_dir( $dir )
{
    $names = array();

    if ( is_dir($dir) && is_readable($dir) )
    {
            foreach ( scandir($dir) as $file )
            {
                    if ( is_dir($dir."/".$file) && is_readable($dir."/".$file) )
                    {
                            $names[] = get_contents_dir($dir."/".$file);
                    }

                    if ( is_file($dir."/".$file) && is_readable($dir."/".$file) )
                    {
                            $names[] = $dir."/".$file;
                    }
            }
    }

    return $names;
}

This function first opens the set $dir folder and scans the list of files, adding each found file to the array which is, after scanning the folder, returned as the return value of the function.

该函数首先打开set $dir文件夹并扫描文件列表,将找到的每个文件添加到数组中,该数组在扫描文件夹后作为函数的返回值返回。

The twist comes in when an entry of the scandir() result (list of files and folders in the folder) is actually a folder. If that happens, the function is called from it's internals, recursively (see the line $names[] = get_contents_dir($dir."/".$file); calling the function from within the function) and the subfolder will be indexed too. Rinse and repeat, until all subfolders are indexed.

当scandir()结果(文件夹中的文件和文件夹列表)的条目实际上是一个文件夹时,就会出现扭曲。如果发生这种情况,函数将从其内部调用(请参见行$names[] = get_contents_dir($dir."/".$file);从函数中调用函数)和子文件夹也将被索引。冲洗并重复,直到所有子文件夹都被索引。

If you call the function and let it execute, an array will be returned. Each key of the array will be an entry. If it was a file, the value linked to the key is the name of the file, if it was a folder, the value will be another array nested into the previous one.

如果您调用函数并让它执行,将返回一个数组。数组的每个键都是一个条目。如果它是一个文件,那么链接到键的值就是文件的名称,如果它是一个文件夹,那么这个值将是嵌套在前一个文件夹中的另一个数组。

Here is an example dump taken of the returned array:

下面是返回数组的一个示例转储:

array (
  0 => './libmysqlclient.so.16.0.0',
  1 => './libmysqlclient_r.so.16.0.0',
  2 => 
  array (
    0 => './libs/libboost_thread-mt.a',
    1 => './libs/libboost_thread-mt.so.1.38.0',
    2 => './libs/libmysql.dll',
    3 => './libs/libmysqlclient16_5.1.41-3ubuntu12_i386.deb',
  ),
  3 => 
  array (
    0 => './radio_sneaker/cl_auto.lua',
    1 => './radio_sneaker/sh_auto.lua',
    2 => './radio_sneaker/sh_coms.lua',
    3 => './radio_sneaker/sh_info.lua',
    4 => './radio_sneaker/sv_auto.lua',
    5 => './radio_sneaker/sv_hooks.lua',
  ),
  4 => './sv_auto.lua',
)

Compare this output against the tree command ran on the same folder:

将此输出与在同一文件夹中运行的树命令进行比较:

|   libmysqlclient.so.16.0.0
|   libmysqlclient_r.so.16.0.0
|   sv_auto.lua
|   
+---libs
|       libboost_thread-mt.a
|       libboost_thread-mt.so.1.38.0
|       libmysql.dll
|       libmysqlclient16_5.1.41-3ubuntu12_i386.deb
|       
\---radio_sneaker
        cl_auto.lua
        sh_auto.lua
        sh_coms.lua
        sh_info.lua
        sv_auto.lua
        sv_hooks.lua

#2


1  

Why don't you use a join function in php to merge the path to check whether it then exists? If it doesn't then go level by level checking if the folder exists and if it doesn't then create in and move further. My point is that creating such a dynamic structure is, first of all, difficult and easy to mess up. Why not to go the easy way?

为什么不使用php中的join函数合并路径以检查它是否存在?如果该文件夹不存在,则按级别检查该文件夹是否存在,如果该文件夹不存在,则创建并进一步移动。我的观点是,创造这样一个动态的结构,首先,是困难和容易搞砸。为什么不走捷径呢?

#3


1  

Imagine that you have an array representing the directory stucture which is initially empty and will be filled in piece by piece. You need to keep track of a "current" item in this array and iterate over the directory names. At each iteration you would create a sub-array under the current item if it does not already exist and then set the current to be this sub-array.

假设您有一个表示目录结构的数组,该结构最初是空的,并将被逐块填充。您需要跟踪这个数组中的“当前”项并遍历目录名。在每次迭代中,如果当前项不存在,您将在当前项下创建一个子数组,然后将当前数组设置为该子数组。

This can be done either with recursion or with iteration, and since it's PHP the "current" marker would need to be a reference.

这可以用递归或迭代来完成,因为它是PHP,所以“当前”标记需要作为参考。

With this overview in mind, have a look at this question and the answers there. The input there is in the form of a string, but that's just an implode away from your current situation.

带着这个概述,看看这个问题和答案。这里的输入是以字符串的形式出现的,但这只是与当前情况的内爆。

#4


1  

I'll let you wrestle this into your code, but heres the important lessons.

我将让您在代码中处理这个问题,但这里有重要的教训。

turn the flat array into a nested structure

将平面数组转换为嵌套结构

$a = array(
    'dir1', 'dir2', 'file.txt'
);

$structure = array(array_pop($a));
foreach (array_reverse($a) as $dir) {
    $structure = array($dir => $structure);
}

print_r($structure);

merge one structure into another

将一个结构合并到另一个结构中。

$result = array_merge_recursive($result, $structure);

Just iterate over all structures for the merging.

只需遍历合并的所有结构。