【问题标题】:Recursively obtain all children from a single parent递归获取单亲的所有孩子
【发布时间】:2020-05-12 15:19:02
【问题描述】:

我有一个文件夹数组,每个文件夹都有一个唯一的 ID 和一个父 ID。我想要做的是从父级找到所有子文件夹,即使子文件夹是子文件夹或子文件夹(无限)。我只需要一个包含所有这些 ID 的数组。

例如,如果我有以下数组

$folders = [
    [
        'id' => 1,
        'parent' => null
    ],
    [
        'id' => 2,
        'parent' => null
    ],
    [
        'id' => 3,
        'parent' => 1
    ],
    [
        'id' => 4,
        'parent' => 3
    ],
    [
        'id' => 5,
        'parent' => 4
    ],
    [
        'id' => 6,
        'parent' => 1
    ]
];

如果我想获取文件夹 ID 1 的所有子项,需要能够循环并获得以下响应:

$children = [3,4,5,6];

我尝试了以下方法:

public function getChildrenIds($folders, $parent_id)
{
    $folderIds = [];
    foreach($folders as $folder) {
        if($folder['parent'] == $parent_id) {
            $folderIds[] = $folder['id'];
        }
    }
    return $folderIds;
}

但我的问题是,我怎样才能使这个恢复?

【问题讨论】:

  • 为什么要递归?您似乎已经有了最佳解决方案。添加递归仅意味着如果您的数组足够长并增加函数调用开销,您可能会破坏堆栈。如果要查找子子子节点,则当前算法将失败,您需要重复循环输入,直到您的开放集为空。那么问题是结构是扁平的,所以如果你想要高效的递归查找,你需要先将结构转换为树。
  • 因为它需要递归,否则它只会得到第一个直接的孩子?
  • 不一定。你也可以使用循环来做到这一点。
  • 数组不能保证完美排序,因为它是通过 API 获得的(我无法控制)。所以一棵树听起来是一个很好的解决方案,我之前也尝试过,但是,我没有取得太大的成功,因为我不确定实现这一目标的最佳方法。
  • 我相信该结构只会真正深入 4-5 层,初始平面阵列包含 30-50 个文件夹。所以我们不是在谈论巨大的数字,但它确实需要是无限的,如果这种情况在未来发生变化。

标签: php arrays recursion tree children


【解决方案1】:

您可以扩展检查以检查目前找到的所有父节点(使用in_array()),而不是使其递归。这使它成为一次通过检查..

public function getChildrenIds($folders, $parent_id)  
{
    // Prime array with parent looking for
    $folderIds = [$parent_id];
    foreach($folders as $folder) {
        // Check if matches any parent so far found
        if( in_array($folder['parent'], $folderIds) ) {
            $folderIds[] = $folder['id'];
        }
    }

    // Remove parent id added at start
    array_shift($folderIds);
    return $folderIds;
}

【讨论】:

  • 这是对参数数组的一次传递,但如果树退化,它仍然是二次的。此外,如果树没有预先排序,逻辑就会失败。
【解决方案2】:

这个版本确实使用了递归,它首先将数组排列为 id 作为键,id 作为值(使用array_column())。

然后,当它将每个父级与 id 匹配时,它将其添加到列表中,然后调用自身添加任何子子级...

public function getChildrenIds($hierarchy, $parent_id)  
{
    $folderIds = [];
    foreach ( $hierarchy as $id => $folder )   {
        if ( $folder == $parent_id )    {
            $folderIds[] = $id;
            $folderIds = array_merge($folderIds, getChildrenIds($hierarchy, $id));
        }
    }

    return $folderIds;
}

忘记添加数组文件夹应该使用...进行转换

$hierarchy = array_column($folders, 'parent', 'id');

被传入。

【讨论】:

  • @ggorlen,不确定您的意思?这不依赖于排序列表。我会对您的解决方案感兴趣。
  • @ggorlen - 最好使用 $folder["id"] 属性 - 为什么?
  • 由于 OP 只有 30-50 个文件夹,我认为这个答案就足够了。转换为树是过早的优化并且是很多代码。话虽如此,我仍然会迭代地做,因为递归和array_merge 是额外的开销。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 2017-04-09
相关资源
最近更新 更多