【问题标题】:Recursive function to generate multidimensional array and count nested children生成多维数组并计算嵌套子级的递归函数
【发布时间】:2013-05-29 19:55:20
【问题描述】:

我不擅长递归,但最近我不得不处理它。

我不得不递归生成一个多维数组,并在这里找到了一种方法:Recursive function to generate multidimensional array from database result

但是我现在还需要计算每个父母有多少孩子,我不知道我将如何采用下面的功能来完成这项工作?

function generateCorrectArray(array $elements, $parentId = 0) {
$branch = array();

foreach ($elements as $key => $element) {
    if ($element['parent'] == $parentId) {
        $children = generateCorrectArray($elements, $element['category_id']);
        if ($children) {
            $element['children'] = $children;
        }
        $branch[$element['category_id']] = $element;
    }
}

return $branch;
}

编辑

我开始的数组:

$someArray = array(
array(
    "id"=> 1,
    "name"=> "somename1",
    "parent"=> 0,
    "childrenCount" => 0,
    "children" => 0
 ),
array(
    "id"=> 53,
    "name"=> "somename2",
    "parent"=> 1,
    "childrenCount" => 0,
    "children" => 0
),
array(
     "id"=> 921,
    "name"=> "somename3",
    "parent"=> 53,
    "childrenCount" => 0,
    "children" => 0
)

当前函数结果

$someArray = array(
array(
"id"=> 1,
"name"=> "somename1",
"parent"=> 0,
"children" => array(
    array(
        "id"=> 53,
        "name"=> "somename2",
        "parent"=> 1,
        "children" => array(
            array(
                "id"=> 921,
                "name"=> "somename3",
                "parent"=> 53,
                "children" => array(

                )
            )
        )
    )
)
)

我希望它也对每个嵌套的子项进行计数。

目标

$someArray = array(
array(
"id"=> 1,
"name"=> "somename1",
"parent"=> 0,
"childrenCount"=> 2,
"children" => array(
    array(
        "id"=> 53,
        "name"=> "somename2",
        "parent"=> 1,
        "childrenCount"=> 1,
        "children" => array(
            array(
                "id"=> 921,
                "name"=> "somename3",
                "parent"=> 53,
                "childrenCount"=> 0,
                "children" => array(

                )
            )
        )
    )
)
)

提前致谢。

【问题讨论】:

    标签: php recursion


    【解决方案1】:

    试试这个:

    function generateCorrectArray(array $elements, $parentId = 0) {
    $branch = array();
    
    foreach ($elements as $key => $element) {
        if ($element['parent'] == $parentId) {
            $children = generateCorrectArray($elements, $element['category_id']);
            if ($children) {
                $element['children'] = $children;
                if(array_key_exists('childrenCount', $element)) {
                    $element['childrenCount'] = $element['childrenCount'] + 1;
                } else {
                    $element['childrenCount'] = 1;
                }
    
            }
            $branch[$element['category_id']] = $element;
        }
    }
    
    return $branch;
    }
    

    【讨论】:

    • 你能粘贴一个示例输入数组,以便我可以在我的机器上运行一些测试...
    【解决方案2】:
    /*
        Gets reversed array,
        Returns multidimensional tree array.
    */
    function buildTree($parts) {
        if (count($parts) == 1) {
            return $parts[0];
        }
        $last_item = array_pop($parts);
        $last_item['childrenCount'] = count($parts);
        $last_item['children'] = buildTree($parts);
        return $last_item;
    }
    

    测试和工作:)

    例子:

    $parts = array(
                array('1','2','3',5),
                array('3','8','3',1),
                array('1', 5,'2','3'),
                array('D','2','3',5),
                array('A','2','3',5)
            );
    
    var_dump(buildTree(array_reverse($parts)));
    

    结果:

    array(6) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "3" [3]=> int(5) ["childrenCount"]=> int(4) ["children"]=> array(6) { [0]=> string(1) "3" [1]=> string(1) "8" [2]=> string(1) "3" [3]=> int(1) ["childrenCount"]=> int(3) ["children"]=> array(6) { [0]=> string(1) "1" [1]=> int(5) [2]=> string(1) "2" [3]=> string(1) "3" ["childrenCount"]=> int(2) ["children"]=> array(6) { [0]=> string(1) "D" [1]=> string(1) "2" [2]=> string(1) "3" [3]=> int(5) ["childrenCount"]=> int(1) ["children"]=> array(4) { [0]=> string(1) "A" [1]=> string(1) "2" [2]=> string(1) "3" [3]=> int(5) } } } } }
    

    【讨论】:

    • 这实际上杀死了我的 Apache,并没有做任何事情,不过谢谢
    【解决方案3】:

    使用递归数组和记录集的一个问题是,除非您只是显示结果,否则您最终会重写大量代码来操作数据。 例如,如果您删除一个孩子,您必须遍历整个数组以更新树的其余部分,或者编写另一个函数来展平数组树以遍历并检索节点属性。 如果您需要查找特定节点的深度或根节点而不仅仅是子节点的数量,会发生什么?

    尝试使用一个对象来存储您的树,该对象可以跟踪继承并执行数组无法执行的功能。当您尝试计算递归以及需要向其添加功能时,这将使处理记录集更容易且耗时更少。

    这是我过去在编写 ORM 之前使用的示例。 https://3v4l.org/PgqlG

    我将它设计为能够迭代整个树(平面数组)、单个节点或节点的子节点。我还需要子数、节点在树中的位置(深度)以及能够找到根节点。希望对您有所帮助。

    /**
     * Provides a flat list of all the nodes
     * Eases with modifying the tree inheritance by id
     */
    class NodeList
    {
    
        public $length = 0;
    
        /**
         * @param mixed $index
         * @return Node|null
         */
        public function item($index)
        {
            $tmp = (array) $this;
            $this->length = count($tmp) - 1;
            if (false === isset($this->$index)) {
                return null;
            }
    
            return $this->$index;
        }
    
    }
    
    /**
     * Establish and maintain the tree view of each node/child
     */
    class Tree extends NodeList
    {
    
        /**
         * Requires id, parent from record set
         * @param null|array|object $recordSet
         */
        public function __construct($recordSet = null)
        {
            if (null !== $recordSet) {
                $this->setChildren($recordSet);
            }
        }
    
        /**
         * @param array|object $recordSet
         */
        private function setChildren($recordSet)
        {
            foreach ($recordSet as $record) {
                if (true === is_array($record)) {
                    $record = (object) $record;
                }
                if (true === isset($record->id)) {
                    $this->length++;
                    $this->appendNode($record->id, $record);
                }
            }
            foreach ($this as $node) {
                if (false === $node instanceof Node) {
                    continue;
                }
                if (false === empty($node->parent) && true === isset($this->{$node->parent})) {
                    $children = &$this->{$node->parent}->children;
                    $children->length++;
                    $children->{$node->id} = &$this->{$node->id};
                    $this->item($node->id);
                }
            }
        }
    
        /**
         * @param string $id
         * @param null|array|object $data
         * @return mixed
         */
        public function appendNode($id, $data = null)
        {
            $this->$id = new Node($data);
    
            return $this->item($id);
        }
    
        /**
         * @param string $id
         * @return \Node
         */
        public function getNode($id)
        {
            $item = $this->item($id);
            if (true === empty($item)) {
                $this->appendNode($id, null);
            }
    
            return $item;
        }
    
        /**
         * @param string $id
         * @return \Node|null
         */
        public function getParent($id)
        {
            if (null === $this->getNode($id)->parent) {
                return null;
            }
    
            return $this->getNode($this->getNode($id)->parent);
        }
    
        /**
         * @param string $id
         * @return int
         */
        public function getDepth($id)
        {
            $i = 0;
            $item = $this->item($id);
            if (null !== $item && null !== $item->parent) {
                $i = $this->getDepth($item->parent) + 1;
            }
            $item->depth = $i;
    
            return $item->depth;
        }
    
        /**
         * @param string $id
         */
        public function removeNode($id)
        {
            $this->removeChildren($id);
            if (null !== $this->item(id)) {
                $parent = false;
                if ($this->item($id)->parent) {
                    $parent = $this->getParent($id);
                }
                $this->$id = null;
                if ($parent && $parent->children) {
                    unset($parent->children->$id);
                    $parent->children->length--;
                }
            }
        }
    
    }
    
    /**
     * Single Node
     * This is an overloaded class
     */
    class Node
    {
    
        public $id;
    
        public $name;
    
        public $parent;
    
        public $depth;
    
        public $children;
    
        /**
         * @param array|object $data
         */
        public function __construct($data)
        {
            $this->children = new NodeList();
            if (null === $data) {
                return;
            }
            foreach ($data as $key => $value) {
                /* I escaped these values since they are redundant to this script */
                switch ($key) {
                    case 'children':
                    case 'depth':
                    case 'childrenCount':
                        continue 2;
                }
                $this->$key = $value;
            }
        }
    
        /**
         * @return int
         */
        public function countChildren()
        {
            return $this->children->length;
        }
    
        /**
         * @return \NodeList
         */
        public function getChildren()
        {
            return $this->children;
        }
    
        public function removeChildren()
        {
            if (null !== $this->getChildren()) {
                foreach ($this->children as $child) {
                    if (true === isset($child->children)) {
                        $child->removeChildren();
                    }
                    $child = null;
                }
            }
            $this->children = null;
    
            return $this;
        }
    
    }
    

    【讨论】:

    • @Neil_Tinkerer 谢谢,我将示例更新为首选小提琴站点,并将代码更新为与 PHP 5.0.2 - 8.0 兼容。请记住,这是近十年前编写的,因此可以进行一些重大更改以改进代码库并遵守当前标准。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 2017-02-16
    • 2012-01-25
    • 1970-01-01
    • 2013-01-15
    相关资源
    最近更新 更多