一个递归函数,用于在数组上使用 foreach 循环对 PHP 中的父节点和子节点进行排序


A recursive function to sort through parent and child nodes in PHP using a foreach loop on an array

我有一个数据存储在一个数组中,该数组使用父子 id 引用自身: idparent_idtitle等。 顶层有0 parent_id,可以有无数的亲子关系。

所以我在递归函数中使用foreach循环对这个数组进行排序,以对照其父元素检查每个数组元素,我认为我已经盯着这种方法太久了。

我最终以正确的顺序获得元素,但我似乎无法正确嵌套我的列表,这让我认为该方法实际上不起作用。

  • 这是最好的路线吗?
  • 我能做些什么来改进和修复此方法
  • 还有别的技巧可以应用吗?

这是我的消息来源:

<div>
    <div>Subpages</div>
    <ul>
    <?php subPages($this->subpages->toArray(), 0) ?>
    </ul>
    <br>
    <a href="javascript:;" onclick="">Add New Subpage</a>
</div>
<?php
    function subPages($subpages, $parent){
        foreach($subpages as $key => &$page){
            $newParent =  $page['id'];
            //If the current page is the parrent start a new list
            if($page['id'] == $parent)
            {
                //Echo out a new list
                echo '<ul>';
                echo '<li class="collapsed">';
                echo '<a href="javascript:;" class="toggle">+</a>';
                echo '<a href="javascript:;" onclick="">'.$page['title'].'</a>';        
                subPages($subpages, $newParent);
                echo '</li>';
                echo '</ul>';
            }
            //If the page's parent id matches the parent provided
            else if($page['parent_id'] == $parent)
            {
                //Echo out the link
                echo '<li class="collapsed">';
                echo '<a href="javascript:;" class="toggle">+</a>';
                echo '<a href="javascript:;" onclick="">'.$page['title'].'</a>';
                //Set the page as the new parent
                $newParent = $page['id'];
                //Remove page from array
                unset($subpages[$key]);
                //Check the rest of the array for children
                subPages($subpages, $newParent);
                echo '</li>';
            }
        }
    }
?>

与往常一样,感谢任何帮助。 如果有什么不清楚的地方,请告诉我。

我怀疑你们是否仍在寻找真正的答案,但它可能会帮助其他人解决同样的问题。下面是一个递归函数,用于将孩子置于父母之下的数组。

$initial = array(
    array(
        'name' => 'People',
        'ID' => 2,
        'parent' => 0
        ),
    array(
        'name' => 'Paul',
        'ID' => 4,
        'parent' => 2
        ),
    array(
        'name' => 'Liz',
        'ID' => 5,
        'parent' => 2
        ),
    array(
        'name' => 'Comus',
        'ID' => 6,
        'parent' => 3
        ),
    array(
        'name' => 'Mai',
        'ID' => 7,
        'parent' => 2
        ),
    array(
        'name' => 'Titus',
        'ID' => 8,
        'parent' => 3
        ),
    array(
        'name' => 'Adult',
        'ID' => 9,
        'parent' => 6
        ),
    array(
        'name' => 'Puppy',
        'ID' => 10,
        'parent' => 8
        ),
    array(
        'name' => 'Programmers',
        'ID' => 11,
        'parent' => 4
        )   ,
    array(
        'name' => 'Animals',
        'ID' => 3,
        'parent' => 0
        )                           
    );

/*---------------------------------
function parentChildSort_r
$idField        = The item's ID identifier (required)
$parentField    = The item's parent identifier (required)
$els            = The array (required)
$parentID       = The parent ID for which to sort (internal)
$result     = The result set (internal)
$depth          = The depth (internal)
----------------------------------*/
function parentChildSort_r($idField, $parentField, $els, $parentID = 0, &$result = array(), &$depth = 0){
    foreach ($els as $key => $value):
        if ($value[$parentField] == $parentID){
            $value['depth'] = $depth;
            array_push($result, $value);
            unset($els[$key]);
            $oldParent = $parentID; 
            $parentID = $value[$idField];
            $depth++;
            parentChildSort_r($idField,$parentField, $els, $parentID, $result, $depth);
            $parentID = $oldParent;
            $depth--;
        }
    endforeach;
    return $result;
}
$result = parentChildSort_r('ID','parent',$initial);
print '<pre>';
print_r($result);
print '</pre>';

这是一种逐渐结束的方法,它从原始数组中删除元素并按正确的顺序将它们放入结果集中。我为您制作了一些通用的内容,因此它只需要您告诉它您的"ID"字段和"父"字段的名称。顶级项的parent_id(无论您如何命名)都必须为 0。 我还为每个项目添加了一个深度标记,以便您可以在输出时格式化。

我会尽力帮助你。

可以在一次传递中组合这样的关系:

    /**
     * Used for "recursive" folding of layout items
     * Algorithm of infinite tree (non recursive method)
     * 
     * @param array $items
     * @return array
     */
    function _foldItems($items) {
        $result = array();
        foreach ($items as $key => $item) {
            $itemName = $item['name'];
            if (!isset($item['parent']))
                continue;
            else {
                $parentName = $item['parent']; // it can be either `name` or some `id` of the parent item
                if (isset($result[$itemName][$item['sequence']])) {
                    // Done to eliminate `Warning: Cannot use a scalar value as an array in atLeisure_PropertyImport.class.php`
                    // Sometimes elements already in the list and have [name] => $count and next line tries to put item in array (item becomes parent)
                    if (    isset($result[$parentName][$item['parentSequence']]['items'][$itemName]) AND
                            is_scalar($result[$parentName][$item['parentSequence']]['items'][$itemName])
                        )
                        $result[$parentName][$item['parentSequence']]['items'][$itemName] = array();
                    $result[$parentName][$item['parentSequence']]['items'][$itemName][$item['sequence']] = $result[$itemName][$item['sequence']];
                    unset($result[$itemName][$item['sequence']]);
                } else
                    $result[$parentName][$item['parentSequence']]['items'][$itemName] = $item['count'];
                unset($items[$key]);
                } // if //
            if (empty($result[$itemName]))
                unset($result[$itemName]);
        } // foreach //
        foreach ($items as $item) { // enumerating rest of the items (single items)
            $itemName = $item['itemName'];
            if (!isset($result[$itemName]))
                $result[$itemName][$item['sequence']] = $item['count'];
        }
        return $result;
    }

示例可能有点难以阅读和理解,因为代码确实太多了,但是不久前我已经为一个项目制作了这个函数,它似乎工作成功。

注意:如果有几个相同的项目链接到一个父项目,它也将起作用。它使用项目序列号来避免将相似的值混为一个。