我通过引用使用递归函数来修改数组时遇到问题

时间:2017-08-06 00:20:35

标签: php arrays

需要一些数组引用专家的帮助。有一天,我的头靠在墙上。我需要将一系列路径转换为数据/子结构。我有来自MySQL的这些记录。

+----+---------------------------------+------------------------------------------------------------------------+
| id | folder                          | path_string                                                            |
+----+---------------------------------+------------------------------------------------------------------------+
|  1 | installfolder                   | INSTALLATION PARTNERS                                                  |
|  2 | installCOIfolder                | INSTALLATION PARTNERS/DOCUMENTS/COI                                    |
|  3 | installDeliveryTicketsfolder    | INSTALLATION PARTNERS/DOCUMENTS/DELIVERY TICKETS                       |
|  4 | installPdfPackagefolder         | INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE                         |
|  5 | installPunchListfolder          | INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE/PDF PUNCHLIST FLOORPLAN |
|  6 | installSitePhotosfolder         | INSTALLATION PARTNERS/SITE PHOTOS                                      |
|  7 | installChangeOrdersfolder       | INSTALLATION PARTNERS/DOCUMENTS/CHANGE ORDERS                          |
|  8 | installCompletionfolder         | INSTALLATION PARTNERS/SITE PHOTOS/COMPLETION                           |
|  9 | installDamagesandWarrantyfolder | INSTALLATION PARTNERS/SITE PHOTOS/DAMAGES & WARRANTY                   |
| 10 | installMarketingfolder          | INSTALLATION PARTNERS/SITE PHOTOS/MARKETING                            |
| 11 | installProgressfolder           | INSTALLATION PARTNERS/SITE PHOTOS/MARKETING                            |
| 12 | meadowsfolder                   | MEADOWS PROJECT DOCUMENTS                                              |
| 13 | meadowsChangeOrdersfolder       | MEADOWS PROJECT DOCUMENTS/CHANGE ORDERS                                |
| 14 | meadowsPunchListfolder          | MEADOWS PROJECT DOCUMENTS/PUNCHLIST                                    |
| 15 | meadowsPunchListItemsfolder     | MEADOWS PROJECT DOCUMENTS/PUNCHLIST ITEMS                              |
+----+---------------------------------+------------------------------------------------------------------------+


DROP TABLE IF EXISTS `validation_paths`;
CREATE TABLE `validation_paths` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `folder` varchar(100) NOT NULL,
  `path_string` varchar(400) DEFAULT NULL,
  `box_id_referer` varchar(100) DEFAULT NULL,
  `title` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `validation_paths` (`id`, `folder`, `path_string`, `box_id_referer`, `title`) VALUES
(1, 'installfolder',    'INSTALLATION PARTNERS',    '', 'Installation Folder'),
(2, 'installCOIfolder', 'INSTALLATION PARTNERS/DOCUMENTS/COI',  '', 'COI Folder'),
(3, 'installDeliveryTicketsfolder', 'INSTALLATION PARTNERS/DOCUMENTS/DELIVERY TICKETS', '', 'Delivery Tickets'),
(4, 'installPdfPackagefolder',  'INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE',   '', 'PDF Installation Packages'),
(5, 'installPunchListfolder',   'INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE/PDF PUNCHLIST FLOORPLAN',   '', 'PDF Floorplans'),
(6, 'installSitePhotosfolder',  'INSTALLATION PARTNERS/SITE PHOTOS',    '', 'Site Photos'),
(7, 'installChangeOrdersfolder',    'INSTALLATION PARTNERS/DOCUMENTS/CHANGE ORDERS',    '', 'Change Orders'),
(8, 'installCompletionfolder',  'INSTALLATION PARTNERS/SITE PHOTOS/COMPLETION', '', 'Completion'),
(9, 'installDamagesandWarrantyfolder',  'INSTALLATION PARTNERS/SITE PHOTOS/DAMAGES & WARRANTY', '', 'Damages & Warranty'),
(10,    'installMarketingfolder',   'INSTALLATION PARTNERS/SITE PHOTOS/MARKETING',  '', 'Marketing'),
(11,    'installProgressfolder',    'INSTALLATION PARTNERS/SITE PHOTOS/MARKETING',  '', 'Progress'),
(12,    'meadowsfolder',    'MEADOWS PROJECT DOCUMENTS',    '', 'Meadows Documents'),
(13,    'meadowsChangeOrdersfolder',    'MEADOWS PROJECT DOCUMENTS/CHANGE ORDERS',  '', 'Meadows Change Orders'),
(14,    'meadowsPunchListfolder',   'MEADOWS PROJECT DOCUMENTS/PUNCHLIST',  '', 'Meadows Punchlists'),
(15,    'meadowsPunchListItemsfolder',  'MEADOWS PROJECT DOCUMENTS/PUNCHLIST ITEMS',    '', 'Meadows Punchlist Items');

目标是得到这个。

stdClass Object
(
    [children] => Array
        (
            [0] => stdClass Object
                (
                    [slug] => installfolder
                    [text] => INSTALLATION PARTNERS
                    [children] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [slug] => installCOIfolder
                                    [text] => DOCUMENTS
                                    [children] => Array
                                        (
                                            [0] => stdClass Object
                                                (
                                                    [slug] => installCOIfolder
                                                    [text] => COI
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [1] => stdClass Object
                                                (
                                                    [slug] => installDeliveryTicketsfolder
                                                    [text] => DELIVERY TICKETS
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [2] => stdClass Object
                                                (
                                                    [slug] => installChangeOrdersfolder
                                                    [text] => CHANGE ORDERS
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [1] => stdClass Object
                                (
                                    [slug] => installPdfPackagefolder
                                    [text] => PDF INSTALLATION PACKAGE
                                    [children] => Array
                                        (
                                            [0] => stdClass Object
                                                (
                                                    [slug] => installPunchListfolder
                                                    [text] => PDF PUNCHLIST FLOORPLAN
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [2] => stdClass Object
                                (
                                    [slug] => installSitePhotosfolder
                                    [text] => SITE PHOTOS
                                    [children] => Array
                                        (
                                            [0] => stdClass Object
                                                (
                                                    [slug] => installCompletionfolder
                                                    [text] => COMPLETION
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [1] => stdClass Object
                                                (
                                                    [slug] => installDamagesandWarrantyfolder
                                                    [text] => DAMAGES & WARRANTY
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [2] => stdClass Object
                                                (
                                                    [slug] => installMarketingfolder
                                                    [text] => MARKETING
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                        )

                )

            [1] => stdClass Object
                (
                    [slug] => meadowsfolder
                    [text] => MEADOWS PROJECT DOCUMENTS
                    [children] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [slug] => meadowsChangeOrdersfolder
                                    [text] => CHANGE ORDERS
                                    [children] => Array
                                        (
                                        )

                                )

                            [1] => stdClass Object
                                (
                                    [slug] => meadowsPunchListfolder
                                    [text] => PUNCHLIST
                                    [children] => Array
                                        (
                                        )

                                )

                            [2] => stdClass Object
                                (
                                    [slug] => meadowsPunchListItemsfolder
                                    [text] => PUNCHLIST ITEMS
                                    [children] => Array
                                        (
                                        )

                                )

                        )

                )

        )

)

现在我想做什么。我使用两个递归函数合并此结构。这是第一个。

function buildTree(array &$array, $parents, $value, $glue = '/')
{
    if (!is_array($parents)) {
        $parents = explode($glue, (string) $parents);
    }

    $ref = &$array;

    foreach ($parents as $key => $parent) {
        if (isset($ref) && !is_array($ref)) {
            $ref = [];
        }

        $ref = &$ref[$parent];
    }

    $ref = $value;
}

$query = "SELECT * FROM validation_paths";

$results = $db->query($query);

$tree = array();

if (!empty($results)){ 
    foreach ($results as $folder){
        buildTree($tree,$folder['path_string'] . '/slug',$folder['folder']);
        buildTree($tree,$folder['path_string'] . '/text',$folder['path_string']);
    }
}   

pruneTree($tree);
echo '<pre>';
print_r($tree);

我从中获得以下

Array
(
    [INSTALLATION PARTNERS] => Array
        (
            [slug] => installfolder
            [text] => INSTALLATION PARTNERS
            [DOCUMENTS] => Array
                (
                    [COI] => Array
                        (
                            [slug] => installCOIfolder
                            [text] => INSTALLATION PARTNERS/DOCUMENTS/COI
                        )

                    [DELIVERY TICKETS] => Array
                        (
                            [slug] => installDeliveryTicketsfolder
                            [text] => INSTALLATION PARTNERS/DOCUMENTS/DELIVERY TICKETS
                        )

                    [CHANGE ORDERS] => Array
                        (
                            [slug] => installChangeOrdersfolder
                            [text] => INSTALLATION PARTNERS/DOCUMENTS/CHANGE ORDERS
                        )

                )

            [PDF INSTALLATION PACKAGE] => Array
                (
                    [slug] => installPdfPackagefolder
                    [text] => INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE
                    [PDF PUNCHLIST FLOORPLAN] => Array
                        (
                            [slug] => installPunchListfolder
                            [text] => INSTALLATION PARTNERS/PDF INSTALLATION PACKAGE/PDF PUNCHLIST FLOORPLAN
                        )

                )

            [SITE PHOTOS] => Array
                (
                    [slug] => installSitePhotosfolder
                    [text] => INSTALLATION PARTNERS/SITE PHOTOS
                    [COMPLETION] => Array
                        (
                            [slug] => installCompletionfolder
                            [text] => INSTALLATION PARTNERS/SITE PHOTOS/COMPLETION
                        )

                    [DAMAGES & WARRANTY] => Array
                        (
                            [slug] => installDamagesandWarrantyfolder
                            [text] => INSTALLATION PARTNERS/SITE PHOTOS/DAMAGES & WARRANTY
                        )

                    [MARKETING] => Array
                        (
                            [slug] => installProgressfolder
                            [text] => INSTALLATION PARTNERS/SITE PHOTOS/MARKETING
                        )

                )

        )

    [MEADOWS PROJECT DOCUMENTS] => Array
        (
            [slug] => meadowsfolder
            [text] => MEADOWS PROJECT DOCUMENTS
            [CHANGE ORDERS] => Array
                (
                    [slug] => meadowsChangeOrdersfolder
                    [text] => MEADOWS PROJECT DOCUMENTS/CHANGE ORDERS
                )

            [PUNCHLIST] => Array
                (
                    [slug] => meadowsPunchListfolder
                    [text] => MEADOWS PROJECT DOCUMENTS/PUNCHLIST
                )

            [PUNCHLIST ITEMS] => Array
                (
                    [slug] => meadowsPunchListItemsfolder
                    [text] => MEADOWS PROJECT DOCUMENTS/PUNCHLIST ITEMS
                )

        )

)
然后我被困了。我使用这个递归函数来根据我的需要改变这个结构但没有很好的结果。

这是功能。

function has_array($arr){
    foreach($arr as $k=>$v){
        if(is_array($v)) {
           return $v;  
        }
    }
    return false;
}


function get_text($txt,$pos=1){
    $parts = explode("/",$txt);
    if(count($parts)){
        return $parts[count($parts)-$pos];
    }
    return $parts;                 
}

function pruneTree(&$nodes) {

    //$nodes = array_values($nodes);

    if(empty($nodes["slug"]) AND $first = has_array($nodes)){
        $nodes["slug"] = $first["slug"];
    }

    $text = get_text($nodes["text"]);
    if(empty($nodes["text"]) AND $first = has_array($nodes)){
        $text = get_text($first["text"],2);
    }

    $nodes["text"] = $text;
    $nodes["children"] = [];

    foreach ($nodes as $key => &$node) {
        if(is_array($node) AND count($node)){
            pruneTree($node);
        }
    }
}    

我从中得到

Array
(
    [INSTALLATION PARTNERS] => Array
        (
            [slug] => installfolder
            [text] => INSTALLATION PARTNERS
            [DOCUMENTS] => Array
                (
                    [COI] => Array
                        (
                            [slug] => installCOIfolder
                            [text] => COI
                            [children] => Array
                                (
                                )

                        )

                    [DELIVERY TICKETS] => Array
                        (
                            [slug] => installDeliveryTicketsfolder
                            [text] => DELIVERY TICKETS
                            [children] => Array
                                (
                                )

                        )

                    [CHANGE ORDERS] => Array
                        (
                            [slug] => installChangeOrdersfolder
                            [text] => CHANGE ORDERS
                            [children] => Array
                                (
                                )

                        )

                    [slug] => installCOIfolder
                    [text] => DOCUMENTS
                    [children] => Array
                        (
                        )

                )

            [PDF INSTALLATION PACKAGE] => Array
                (
                    [slug] => installPdfPackagefolder
                    [text] => PDF INSTALLATION PACKAGE
                    [PDF PUNCHLIST FLOORPLAN] => Array
                        (
                            [slug] => installPunchListfolder
                            [text] => PDF PUNCHLIST FLOORPLAN
                            [children] => Array
                                (
                                )

                        )

                    [children] => Array
                        (
                        )

                )

            [SITE PHOTOS] => Array
                (
                    [slug] => installSitePhotosfolder
                    [text] => SITE PHOTOS
                    [COMPLETION] => Array
                        (
                            [slug] => installCompletionfolder
                            [text] => COMPLETION
                            [children] => Array
                                (
                                )

                        )

                    [DAMAGES & WARRANTY] => Array
                        (
                            [slug] => installDamagesandWarrantyfolder
                            [text] => DAMAGES & WARRANTY
                            [children] => Array
                                (
                                )

                        )

                    [MARKETING] => Array
                        (
                            [slug] => installProgressfolder
                            [text] => MARKETING
                            [children] => Array
                                (
                                )

                        )

                    [children] => Array
                        (
                        )

                )

            [children] => Array
                (
                )

        )

    [MEADOWS PROJECT DOCUMENTS] => Array
        (
            [slug] => meadowsfolder
            [text] => MEADOWS PROJECT DOCUMENTS
            [CHANGE ORDERS] => Array
                (
                    [slug] => meadowsChangeOrdersfolder
                    [text] => CHANGE ORDERS
                    [children] => Array
                        (
                        )

                )

            [PUNCHLIST] => Array
                (
                    [slug] => meadowsPunchListfolder
                    [text] => PUNCHLIST
                    [children] => Array
                        (
                        )

                )

            [PUNCHLIST ITEMS] => Array
                (
                    [slug] => meadowsPunchListItemsfolder
                    [text] => PUNCHLIST ITEMS
                    [children] => Array
                        (
                        )

                )

            [children] => Array
                (
                )

        )

    [slug] => installfolder
    [text] => 
    [children] => Array
        (
        )

)

任何人都能给我一个正确方向的暗示吗?感谢。

2 个答案:

答案 0 :(得分:2)

由于对象本身作为引用传递,因此您只需要使用路径段(关系数据)找到正确的对象。最简单的方法是使用这些路径作为索引,您可以在后续迭代中参考这些索引。试试这个功能:

function buildTree($data) {
    $tree = new StdClass;
    $index = [];
    foreach ($data as $item) {
        $node = $tree;
        $path = '';
        foreach (explode('/', $item['path_string']) as $segment) {
            $path .= empty($path) ? $segment : '/' . $segment;
            if (!isset($index[$path])) {
                $index[$path] = new stdClass;
                $index[$path]->slug = $item['folder'];
                $index[$path]->text = $segment;
                $index[$path]->children = [];
                $node->children[] = $index[$path]
            }
            $node = $index[$path];
        }
    }

    return $tree;
}

在您的示例中,INSTALLATION PARTNERS/DOCUMENTS没有数据,因此它将保留为空节点(仅限子节点)。如果这不是一个错误提供一些信息,因为我不知道如何解决它的属性,所以它可以匹配预期的结果。

答案 1 :(得分:1)

首先还有其他方法可以做到这一点,但为了保持工作流程,我会修改buildTree函数来存储所需的所有数据。为此,您可以使用此答案from 'Using a string path to set nested array data'

function set_nested_array_value(&$array, $path, &$value, $delimiter = '/') {
    $pathParts = explode($delimiter, $path);

    $current = &$array;
    foreach($pathParts as $key) {
        $current = &$current[$key];
    }

    $backup = $current;
    $current = $value;

    return $backup;
}

现在您可以调用此函数并使用该值来存储您的slug,在这种情况下我使用['folder'=>$path['folder']],所以现在您有:

function buildTree($results){
    $data = [];
    foreach($results as $path){
        $r = [];
        $v = ['folder'=>$path['folder']];
        $res = set_nested_array_value($r, $path['path_string'], $v);
        $data = array_merge_recursive($data, $r);
   }  
   return $data;
}

然后修改pruneTree以创建带子项的stdClass对象:

function pruneTree( $array){
    $result = []; $i = 0;

    foreach($array as $key=>$node){
       $r = [];
       // set the slug if it exists
        if(isset( $node['folder'])){
            $r['slug'] = $node['folder'];
            unset($node['folder']);
        }
        $r['text']  = $key;
        // set the children through recursion
        $r['children'] = pruneTree($node);

        // when the node does not have slug (ie: DOCUMENTS)
        // set the slug of the first child - to match expected results.
        if(!isset($r['slug']) && isset($r['children'][0])){
            $r['slug'] =  $r['children'][0]->slug;
        }
        // transform to object - to match expected results.
        $result[$i] =(object) $r;  
        $i++;
    }

    return $result;
}

现在为了符合您的预期结果,您可以:

$r = [
    'children' => pruneTree(buildTree($results))
];
print_r((object)$r); 

这里是gist