简体   繁体   English

使用父级从数组中获取子级列表,而无需在PHP中进行递归

[英]Getting a list of children from an array with Parents, without recursion in PHP

I have a situation where I have already obtained and manipulated SQL data into an array and into a tree. 我遇到的一种情况是,我已经获取并操纵了SQL数据到数组和树中。 I am trying to avoid recursion at all costs because it has bitten me in the behind in the past. 我试图不惜一切代价避免递归,因为它过去使我陷入了困境。

I have an array of elements with Parent_IDs, and I'd like to be able to obtain a list of all of their children and subchildren. 我有一个带有Parent_ID的元素数组,并且我希望能够获得其所有子代和子代的列表。 It shouldnt be nearly as complex as going the other way (from an array to a nested tree) which I got without issue using references, but for some reason I'm brain-frozen... 它不应该像其他方式那样复杂(从数组到嵌套树),使用引用我没有问题,但是由于某种原因,我被冻结了……

Any help appreciated. 任何帮助表示赞赏。

I have the data in two possible formats because I have manipulated it already. 我有两种可能的格式的数据,因为我已经对其进行了处理。 Whichver is best for input can be used. 可以使用最合适的输入。 this is a structure (print_r) of the two arrays I have: 这是我拥有的两个数组的结构(print_r):

Array
(
    [202735] => Array
        (
            [ID] => 202735
            [text] => aaafdf
            [Parent] => 
        )

    [202737] => Array
        (
            [ID] => 202737
            [text] => Filho 2
            [Parent] => 202735
        )

    [202733] => Array
        (
            [ID] => 202733
            [text] => Neto 1
            [Parent] => 202731
        )

    [202739] => Array
        (
            [ID] => 202739
            [text] => Neto 2
            [Parent] => 202737
        )

)

or 要么

Array
(
    [0] => Array
        (
            [ID] => 202735
            [text] => aaafdf
            [Parent] => 
            [children] => Array
                (
                    [0] => Array
                        (
                            [ID] => 202737
                            [text] => Filho 2
                            [Parent] => 202735
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [ID] => 202739
                                            [text] => Neto 2
                                            [Parent] => 202737
                                        )

                                )

                        )

                )

        )

    [1] => Array
        (
            [ID] => 202733
            [text] => Neto 1
            [Parent] => 202731
        )

)

Desired output in the format: (first level parent => all children and grandchildren) 所需的输出格式:(一级父级=>所有子级和子级)

array(202731=>array(202735));
array(202735=>array(202737,202739));

or similar... Ideally i'll wrap this in a function like ListChildren($InitialParent), and return all children from such... invoking ListChildren(0) or (null) would list all elements and all subs... 或类似...理想情况下,我会将其包装在ListChildren($ InitialParent)之类的函数中,并从此类返回所有子级...调用ListChildren(0)或(null)将列出所有元素和所有子项...

(additional array elements can be ignored for the purpose of this exercise) (在本练习中,可以忽略其他数组元素)

OBS: some data in the array is missing... namely the category above 202735, which would be 202731, but thats just because i limited the data I copied in... basically I can have either a flat array with parent ids, or a "tree" array with nested children as the source. OBS:数组中的某些数据丢失了……即202735以上的类别,将是202731,但这仅仅是因为我限制了复制的数据……基本上我可以拥有带有父ID的平面数组,或者一个以嵌套子代为源的“树”数组。

I ended up with this. 我结束了这个。 Thanks for the help, in the end I reverted to a recursive code. 感谢您的帮助,最后我恢复了递归代码。 I'll monitor it for performance although I suppose just within the PHP layer it wont be an issue. 我将监视它的性能,尽管我认为只是在PHP层内这不是问题。 I had a bad experience when I went in for maintenance on a project that had DB calls in a recursive function... as the usage grew the recursvie function usage grew exponentially and the DB calls went to 100s of thousands... 当我去维护一个具有递归函数的DB调用的项目时,我的经历很糟糕……随着使用量的增长,recursvie函数的使用量呈指数增长,并且DB调用达到数十万...

anyways: 无论如何:

    function __GetChildrenRec($Lista, $Categoria){
        // Return false if $initialParent doesn't exist
        if ($Categoria == 0) $Categoria = "";
        if (!isset($Lista[$Categoria])) return FALSE;

        // Loop data and assign children by reference
        foreach ($Lista as $CategAtual) {
            if ($CategAtual[Parent] == $Categoria) {
                $Filhos[] = $CategAtual[ID];
                $Filhos = array_merge((array)$Filhos,(array)self::__GetChildrenRec($Lista, $CategAtual[ID]));
            }
        }

        // Return the data
        return is_array($Filhos) ? $Filhos : array();
    }

There really is no reason to avoid recursion unless it is causing you a genuine performance problem. 除非没有引起真正的性能问题,否则确实没有理由避免递归。 Recursion is how most developers looking at problems of this nature would probably attempt to solve them, and using alternative approaches can hurt maintainability because your code is doing something that someone who needs to maintain your code at a later date doesn't expect. 递归是大多数开发人员着眼于此类问题的方式,他们可能会尝试解决这些问题,并且使用替代方法可能会损害可维护性,因为您的代码正在执行某些事,而这是某些人以后需要维护您的代码所无法预期的。

Generally speaking, unrolling recursion means managing a stack. 一般来说,展开递归意味着管理堆栈。 Recursion is a way of getting the language you're using to manage the stack for you, if you don't use recursion, then you'll need to manipulate a stack yourself inside your function. 递归是一种获取用于管理堆栈的语言的方法,如果您不使用递归,则需要在函数内部自己操作堆栈。 The simplest way of doing this is with array_push and array_pop, functions built into PHP that let you use an array as a stack. 最简单的方法是使用array_push和array_pop,这是PHP内置的函数,可让您将数组用作堆栈。

The stack-based approach is rather complex compared to simply using recursion though, and if recursion is giving you problems then manually maintaining a stack certainly will. 与仅使用递归相比,基于堆栈的方法相当复杂,如果递归给您带来了问题,那么手动维护堆栈肯定会。 There are benefits to be sure, but honestly I'd suggest that you try to figure out recursion instead, as it really is easier to deal with, and while it isn't as performant as managing a stack yourself, the performance loss in probably not going to be a bottleneck in your code as the bottlenecks in PHP scripts tend to be where PHP interfaces with the outside world (databases, files, network connections, etc). 可以肯定会有好处,但是老实说,我建议您尝试找出递归,因为它确实更容易处理,尽管它不如自己管理堆栈那样高效,但可能会降低性能不会成为代码的瓶颈,因为PHP脚本中的瓶颈往往是PHP与外界(数据库,文件,网络连接等)进行交互的地方。

Using the first array format: 使用第一种数组格式:

function list_children ($array, $initialParent) {

  // Return false if $initialParent doesn't exist
  if (!isset($array[$initialParent])) return FALSE;

  // Loop data and assign children by reference
  foreach ($array as &$item) {
    if (isset($array[$item['parent']])) {
      if (!isset($array[$item['parent']]['children'])) $array[$item['parent']]['children'] = array();
      $array[$item['parent']]['children'][] = &$item;
    }
  }

  // Return the data
  return (isset($array[$initialParent]['children'])) ? $array[$initialParent]['children'] : array();

}

What this does is basically create the second array from the first, but it does it by reference - so the initial parent can still be found by it's ID, and returned. 这样做基本上是从第一个数组创建第二个数组,但是它是通过引用完成的-因此仍可以通过其ID找到初始父对象​​并返回。 Returns the array of children, an empty array() if there are no children, or FALSE if the $initialParent doesn't exist. 返回子项array()如果没有子项,则返回空array()如果$initialParent不存在,则返回FALSE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM