使用给定的深度,根和父级子级数量在PHP中创建树结构

时间:2019-07-09 11:22:33

标签: php tree

我有一个用户,我将考虑我的树结构的根元素。 之后,我从数据库中获得了一系列用户,这些用户考虑了树的所有子元素。

树的构建需要包含以下确定树的宽度和深度的变量:

Variable: MATCHES_TREE_MAX_DEPTH (eg: 3)
Variable: MATCHES_TREE_ROOT_MAX_CHILDREN_AMOUNT (eg: 2)
Variable: MATCHES_TREE_PARENT_MAX_CHILDREN_AMOUNT (eg: 1)

这意味着我想创建一个深度为3的树结构(这包括根元素,因此我想更深2级)。根元素有2个子元素,而任何子元素的子元素最多具有1个子元素。

这些项在我的用户数组中的顺序是我要在树中插入它们的顺序(我想先将它们插入广度而不是深度)。

我在SO上找到了以下通用函数:PHP - How to build tree structure list? 但是我似乎无法使其适应我的用例,因为我没有来自数据库的父子关系。

这个SO答案返回了一个看起来相似的数组,但是在将其重新设置为用例时遇到了问题: PHP generate a tree by specified depth and rules

示例数据如下:

根用户:

object(stdClass)[56]
  public 'user_id' => string '1' (length=1)
  public 'first_name' => string 'Dennis' (length=6)

其他用户(孩子):

array (size=3)
  0 => 
    object(stdClass)[57]
      public 'user_id' => string '2' (length=2)
      public 'first_name' => string 'Tom' (length=3)
      public 'street' => string 'Teststreet' (length=10)
  1 => 
    object(stdClass)[58]
      public 'user_id' => string '3' (length=2)
      public 'first_name' => string 'Mary' (length=1)
      public 'street' => string 'Maryland avenue' (length=15)
  2 => 
    object(stdClass)[59]
      public 'user_id' => string '4' (length=2)
      public 'first_name' => string 'Jeff' (length=4)
      public 'street' => string 'Teststreet' (length=10)

我想用填充的示例来实现的树的示例(考虑了3个最大深度,2个root子节点和1个max子节点(除root以外的任何元素)的变量):

Array
(
    [userid] => 1
    [name] => "Dennis"
    [matches] => Array
        (
            [0] => Array
                (
                    [userid] => 2
                    [name] => "Tom"
                    [street] => "Teststreet"
                    [matches] => Array
                        (
                            [0] => Array
                                (
                                    [userid] => 4
                                    [name] => "Jeff"
                                    [street] => "Teststreet"
                                    [matches] = Array()
                                )
                        )
                )

            [1] => Array
                (
                    [userid] => 3
                    [name] => "Mary"
                    [street] => "Maryland avenue"
                    [matches] => Array
                        (
                        )
                )
        )
)

在给定确定深度和子级的3个变量的情况下,如何创建这种树形结构?

1 个答案:

答案 0 :(得分:1)

编辑:我看到原来的问题正在寻找与3个常数一起使用的解决方案。我已经添加了代码,因此可以定义常量并基于它们进行循环,但是我不确定我是否应该理解如何使用所有三个变量。特别是,根据您的描述, MATCHES_TREE_MAX_DEPTH 似乎不合适。您仅指示了两个级别的孩子,并指示我们应该跳过列表中的所有其他项目。如果您想要定义更多子级的代码,则需要更清楚地了解结构的增长方式。

鉴于在附加注释中对此问题描述的范围非常狭窄,似乎为解决该问题而烦恼循环很费力。这棵树不能有五个以上的元素,因此这样的迭代解决方案应该起作用:

// function to convert from list objects to the array we want as output
function new_obj($obj) {
    $ret = array(
        "userid" => $obj->user_id,
        "name" => $obj->first_name
    );
    if (isset($obj->street)) {
        $ret["street"] = $obj->street;
    }
    $ret["matches"] = [];
    return $ret;
}


// INPUT DATA
$root = (object)["user_id" => "1", "first_name" => "Dennis"];
$children = [
    (object)[
        "user_id" => "2",
        "first_name" => "Tom",
        "street" => "Teststreet"
    ],
    (object)[
        "user_id" => "3",
        "first_name" => "Mary",
        "street" => "Maryland avenue"
    ],
    (object)[
        "user_id" => "4",
        "first_name" => "Jeff",
        "street" => "Teststreet"
    ],
    (object)[
        "user_id" => "5",
        "first_name" => "Arthur",
        "street" => "Teststreet"
    ]

];

$result1 = new_obj($root);

// an iterative solution, only works for one trivial set of values for the constants defined
// but also does provide some insight into a more general solution
if (isset($children[0])) {
    $result1["matches"][0] = new_obj($children[0]);
}
if (isset($children[1])) {
    $result1["matches"][1] = new_obj($children[1]);
}
if (isset($children[2])) {
    $result1["matches"][0]["matches"][0] = new_obj($children[2]);
}
if (isset($children[3])) {
    $result1["matches"][1]["matches"][0] = new_obj($children[3]);
}


print_r($result1);

如果要定义常量/变量以指定子限制,然后使用循环,请尝试使用与上面定义的相同的$ root和$ children变量。

// solution must use these constants:
define("MATCHES_TREE_MAX_DEPTH", 3);
define("MATCHES_TREE_ROOT_MAX_CHILDREN_AMOUNT", 2);
define("MATCHES_TREE_PARENT_MAX_CHILDREN_AMOUNT", 1);

$result2 = new_obj($root);

$i = 0;
while ($child = array_shift($children)) {
    $result2["matches"][$i] = new_obj($child);
    $i++;
    if ($i >= MATCHES_TREE_ROOT_MAX_CHILDREN_AMOUNT) break;
}

$i = 0;
while ($grandchild = array_shift($children)) {
    $child = $result2["matches"][$i];
    if (count($child["matches"]) >= MATCHES_TREE_PARENT_MAX_CHILDREN_AMOUNT) {
        // if we reach a child that has its max number of grandchildren, it's time to quit
        break;
    }
    // otherwise, assign this child as a grandchild
    $result2["matches"][$i]["matches"] = new_obj($grandchild);

    // increment the counter and check if we cycle back to the first child of root
    $i++;
    if ($i >= count($result2["matches"])) {
        $i = 0;
    }
}
print_r($result2);