2

我不擅长递归,但最近我被要求处理太多。

我不得不递归地生成一个多维数组并在这里找到了一种方法: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(

                )
            )
        )
    )
)
)

先谢谢了。

4

3 回答 3

1

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

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

这是我过去在编写 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;
    }

}
于 2013-11-27T16:14:27.537 回答
0

尝试这个:

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;
}
于 2013-06-03T15:48:12.560 回答
0
/*
    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) } } } } }
于 2013-06-03T15:49:29.260 回答