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

前端 未结 2 1374
梦毁少年i
梦毁少年i 2021-01-07 10:18

I have a data set stored in an array that references itself with parent-child ids: id, parent_id, title etc. The top tier has a

相关标签:
2条回答
  • 2021-01-07 10:42

    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.

    0 讨论(0)
  • 2021-01-07 10:48

    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.

    0 讨论(0)
提交回复
热议问题