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

雨燕双飞 提交于 2019-12-01 01:35:54

I doubt that you guys are still looking for a real answer to this, but it might help out others with the same problem. Below is a recursive function to resort an array placing children beneath parents.

$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>';

It's a wind down method that removes elements from the original array and places them into result set in the proper order. I made it somewhat generic for you, so it just needs you to tell it what your 'ID' field and 'parent' fields are called. Top level items are required to have a parent_id (however you name it) of 0. I also add a depth marker to each item so that you can format on output.

I will try to help you.

It is possible to compose such relations in one pass:

    /**
     * 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;

    }

Example can be a bit hard to read and to understand because there is really too much code, but I've made this function not so long ago for one project and it seems to be work successfully.

NOTE: It will also work if there are several same items linked to one parent item. It uses item sequence number to avoid aliasing similar values into one.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!