복붙노트

일련의 부모 - 자식 관계를 계층 트리로 변환 하시겠습니까?

PHP

일련의 부모 - 자식 관계를 계층 트리로 변환 하시겠습니까?

이름 - 부모 이름 쌍이 많아 가능한 한 많은 계층 구조 트리 구조로 전환하고 싶습니다. 예를 들어, 다음과 같은 쌍이 될 수 있습니다.

Child : Parent
    H : G
    F : G
    G : D
    E : D
    A : E
    B : C
    C : E
    D : NULL

어느 것이 (a) 계층 적 트리로 변형 될 필요가 있는가?

D
├── E
│   ├── A
│   │   └── B
│   └── C   
└── G
    ├── F
    └── H

최종 결과는 중첩 된

    요소 집합이며 각
  • 에는 자식 이름이 들어 있습니다.

    쌍 (아이는 자신의 부모, 부모는 아이의 자식 등)에 모순이 없으므로 여러 최적화가 이루어질 수 있습니다.

    PHP에서 child => parent 쌍을 포함하는 배열을 중첩 된

      집합으로 변환하는 방법은 무엇입니까?

      나는 재귀가 관련되어 있다는 느낌을 가지고 있지만, 나는 그것을 완전히 생각할만큼 충분히 깨어 있지 않다.

      해결법

      1. ==============================

        1.이것은 자식 구조 / 부모 구조를 트리 구조로 파싱하는 또 다른 재귀 함수를 출력하는 아주 기본적인 재귀 함수를 필요로합니다. 하나의 함수로 충분하지만 여기서는 명확성을 위해 두 가지를 사용합니다 (이 함수의 끝에는 결합 된 함수가 있습니다).

        이것은 자식 구조 / 부모 구조를 트리 구조로 파싱하는 또 다른 재귀 함수를 출력하는 아주 기본적인 재귀 함수를 필요로합니다. 하나의 함수로 충분하지만 여기서는 명확성을 위해 두 가지를 사용합니다 (이 함수의 끝에는 결합 된 함수가 있습니다).

        먼저 자식 / 부모 쌍의 배열을 초기화합니다.

        $tree = array(
            'H' => 'G',
            'F' => 'G',
            'G' => 'D',
            'E' => 'D',
            'A' => 'E',
            'B' => 'C',
            'C' => 'E',
            'D' => null
        );
        

        그런 다음 해당 배열을 계층 적 트리 구조로 구문 분석하는 함수는 다음과 같습니다.

        function parseTree($tree, $root = null) {
            $return = array();
            # Traverse the tree and search for direct children of the root
            foreach($tree as $child => $parent) {
                # A direct child is found
                if($parent == $root) {
                    # Remove item from tree (we don't need to traverse this again)
                    unset($tree[$child]);
                    # Append the child into result array and parse its children
                    $return[] = array(
                        'name' => $child,
                        'children' => parseTree($tree, $child)
                    );
                }
            }
            return empty($return) ? null : $return;    
        }
        

        정렬되지 않은 목록을 인쇄하기 위해 그 트리를 가로 지르는 함수 :

        function printTree($tree) {
            if(!is_null($tree) && count($tree) > 0) {
                echo '<ul>';
                foreach($tree as $node) {
                    echo '<li>'.$node['name'];
                    printTree($node['children']);
                    echo '</li>';
                }
                echo '</ul>';
            }
        }
        

        실제 사용량 :

        $result = parseTree($tree);
        printTree($result);
        

        $ result의 내용은 다음과 같습니다.

        Array(
            [0] => Array(
                [name] => D
                [children] => Array(
                    [0] => Array(
                        [name] => G
                        [children] => Array(
                            [0] => Array(
                                [name] => H
                                [children] => NULL
                            )
                            [1] => Array(
                                [name] => F
                                [children] => NULL
                            )
                        )
                    )
                    [1] => Array(
                        [name] => E
                        [children] => Array(
                            [0] => Array(
                                [name] => A
                                [children] => NULL
                            )
                            [1] => Array(
                                [name] => C
                                [children] => Array(
                                    [0] => Array(
                                        [name] => B
                                        [children] => NULL
                                    )
                                )
                            )
                        )
                    )
                )
            )
        )
        

        좀 더 효율성을 원한다면, 그 함수들을 하나로 결합하고 반복 횟수를 줄일 수 있습니다 :

        function parseAndPrintTree($root, $tree) {
            $return = array();
            if(!is_null($tree) && count($tree) > 0) {
                echo '<ul>';
                foreach($tree as $child => $parent) {
                    if($parent == $root) {                    
                        unset($tree[$child]);
                        echo '<li>'.$child;
                        parseAndPrintTree($child, $tree);
                        echo '</li>';
                    }
                }
                echo '</ul>';
            }
        }
        

        이처럼 작은 8 개의 반복 만 데이터 세트에 저장하지만 더 큰 세트에서는 차이를 만들 수 있습니다.

      2. ==============================

        2.트리를 만드는 또 다른 함수 (재귀가 필요없고 대신 참조를 사용함) :

        트리를 만드는 또 다른 함수 (재귀가 필요없고 대신 참조를 사용함) :

        $array = array('H' => 'G', 'F' => 'G', ..., 'D' => null);
        
        function to_tree($array)
        {
            $flat = array();
            $tree = array();
        
            foreach ($array as $child => $parent) {
                if (!isset($flat[$child])) {
                    $flat[$child] = array();
                }
                if (!empty($parent)) {
                    $flat[$parent][$child] =& $flat[$child];
                } else {
                    $tree[$child] =& $flat[$child];
                }
            }
        
            return $tree;
        }
        

        다음과 같은 계층 적 배열을 반환합니다.

        Array(
            [D] => Array(
                [G] => Array(
                    [H] => Array()
                    [F] => Array()
                )
                ...
            )
        )
        

        재귀 함수를 사용하여 쉽게 HTML 목록으로 인쇄 할 수 있습니다.

      3. ==============================

        3.$ 트리의 플랫 구조를 계층 구조로 변환하는 또 다른 단순화 된 방법. 노출을 위해서는 하나의 임시 배열 만 필요합니다.

        $ 트리의 플랫 구조를 계층 구조로 변환하는 또 다른 단순화 된 방법. 노출을 위해서는 하나의 임시 배열 만 필요합니다.

        // add children to parents
        $flat = array(); # temporary array
        foreach ($tree as $name => $parent)
        {
            $flat[$name]['name'] = $name; # self
            if (NULL === $parent)
            {
                # no parent, is root element, assign it to $tree
                $tree = &$flat[$name]; 
            }
            else
            {
                # has parent, add self as child    
                $flat[$parent]['children'][] = &$flat[$name];
            }
        }
        unset($flat);
        

        계층 구조를 다차원 배열로 가져 오는 것은 다음과 같습니다.

        Array
        (
            [children] => Array
                (
                    [0] => Array
                        (
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [name] => H
                                        )
        
                                    [1] => Array
                                        (
                                            [name] => F
                                        )
        
                                )
        
                            [name] => G
                        )
        
                    [1] => Array
                        (
                            [name] => E
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [name] => A
                                        )
        
                                    [1] => Array
                                        (
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [name] => B
                                                        )
        
                                                )
        
                                            [name] => C
                                        )
        
                                )
        
                        )
        
                )
        
            [name] => D
        )
        

        재귀를 피하려면 출력이 작습니다 (큰 구조에서는 부담이 될 수 있음).

        나는 배열을 출력하기 위해 항상 UL / LI "딜레마"를 풀고 싶었습니다. 딜레마는 각 항목이 어린이가 후속 조치를 취할지 또는 선행 요소를 몇 개 닫아야하는지 여부를 알지 못한다는 것입니다. 또 다른 대답은 이미 RecursiveIteratorIterator를 사용하고 getDepth () 및 기타 작성한 Iterator에서 제공 한 메타 정보를 찾고 해결했습니다. 중첩 된 모델을

          에 넣되 "닫힌"하위 트리는 숨겨 둡니다. 그 대답은 반복자를 사용하면 매우 유연하다는 것을 보여줍니다.

          그러나 그것은 미리 정렬 된 목록 이었으므로 귀하의 예에 적합하지 않습니다. 또한 표준 트리 구조와 HTML의

          • 요소에 대해이 문제를 해결하기를 항상 원했습니다.

            내가 내놓은 기본 개념은 다음과 같다.

            우선 주 출력 로직부터 시작합니다. 이제 계층 적 $ 트리 배열을 사용하면 최종 코드는 다음과 같이 보입니다.

            $root = new TreeNode($tree);
            $it = new TreeNodesIterator(array($root));
            $rit = new RecursiveListIterator($it);
            $decor = new ListDecorator($rit);
            $rit->addDecorator($decor);
            
            foreach($rit as $item)
            {
                $inset = $decor->inset(1);
                printf("%s%s\n", $inset, $item->getName());
            }
            

            먼저

            • 요소를 래핑하고 목록 구조가 출력되는 방식을 결정하는 ListDecorator에 대해 살펴 보겠습니다.

              class ListDecorator
              {
                  private $iterator;
                  public function __construct(RecursiveListIterator $iterator)
                  {
                      $this->iterator = $iterator;
                  }
                  public function inset($add = 0)
                  {
                      return str_repeat('  ', $this->iterator->getDepth()*2+$add);
                  }
              

              생성자는 작업중인 iterator를 취합니다. 인셋은 출력을 들여 쓰기하기위한 도우미 함수 일뿐입니다. 나머지는 각 이벤트의 출력 함수입니다.

                  public function beginElement()
                  {
                      printf("%s<li>\n", $this->inset());
                  }
                  public function endElement()
                  {
                      printf("%s</li>\n", $this->inset());
                  }
                  public function beginChildren()
                  {
                      printf("%s<ul>\n", $this->inset(-1));
                  }
                  public function endChildren()
                  {
                      printf("%s</ul>\n", $this->inset(-1));
                  }
                  public function beginIteration()
                  {
                      printf("%s<ul>\n", $this->inset());
                  }
                  public function endIteration()
                  {
                      printf("%s</ul>\n", $this->inset());
                  }
              }
              

              이러한 출력 기능을 염두에두고, 이것은 주요 출력 후 처리 / 루프입니다. 단계별로 살펴 보겠습니다.

              $root = new TreeNode($tree);
              

              반복을 시작할 때 사용할 루트 TreeNode를 만듭니다.

              $it = new TreeNodesIterator(array($root));
              

              이 TreeNodesIterator는, 단일의 $ 루트 노드에 재귀 적 반복을 가능하게하는 RecursiveIterator입니다. 이 클래스는 반복을 위해 무언가가 필요하고 TreeNode 요소의 배열 인 자식 집합과 함께 다시 사용할 수 있으므로 배열로 전달됩니다.

              $rit = new RecursiveListIterator($it);
              

              이 RecursiveListIterator는 상기 이벤트를 제공하는 RecursiveIteratorIterator입니다. 이를 사용하려면 ListDecorator 만 제공 (위의 클래스)하고 addDecorator로 할당해야합니다.

              $decor = new ListDecorator($rit);
              $rit->addDecorator($decor);
              

              그러면 모든 것을 설정하고 각 노드를 출력합니다.

              foreach($rit as $item)
              {
                  $inset = $decor->inset(1);
                  printf("%s%s\n", $inset, $item->getName());
              }
              

              이 예제에서 보듯이 전체 출력 로직은 ListDecorator 클래스와이 단일 foreach로 캡슐화됩니다. 전체 재귀 적 트래버스는 내부적으로 재귀 함수 호출이 수행되지 않는다는 것을 의미하는 스택 된 프로 시저를 제공하는 SPL 재귀 반복자로 완전히 캡슐화되었습니다.

              이벤트 기반 ListDecorator를 사용하면 특별히 출력을 수정하고 동일한 데이터 구조에 대해 여러 유형의 목록을 제공 할 수 있습니다. 배열 데이터가 TreeNode에 캡슐화되어 입력을 변경할 수도 있습니다.

              전체 코드 예 :

              <?php
              namespace My;
              
              $tree = array('H' => 'G', 'F' => 'G', 'G' => 'D', 'E' => 'D', 'A' => 'E', 'B' => 'C', 'C' => 'E', 'D' => null);
              
              // add children to parents
              $flat = array(); # temporary array
              foreach ($tree as $name => $parent)
              {
                  $flat[$name]['name'] = $name; # self
                  if (NULL === $parent)
                  {
                      # no parent, is root element, assign it to $tree
                      $tree = &$flat[$name];
                  }
                  else
                  {
                      # has parent, add self as child    
                      $flat[$parent]['children'][] = &$flat[$name];
                  }
              }
              unset($flat);
              
              class TreeNode
              {
                  protected $data;
                  public function __construct(array $element)
                  {
                      if (!isset($element['name']))
                          throw new InvalidArgumentException('Element has no name.');
              
                      if (isset($element['children']) && !is_array($element['children']))
                          throw new InvalidArgumentException('Element has invalid children.');
              
                      $this->data = $element;
                  }
                  public function getName()
                  {
                       return $this->data['name'];
                  }
                  public function hasChildren()
                  {
                      return isset($this->data['children']) && count($this->data['children']);
                  }
                  /**
                   * @return array of child TreeNode elements 
                   */
                  public function getChildren()
                  {        
                      $children = $this->hasChildren() ? $this->data['children'] : array();
                      $class = get_called_class();
                      foreach($children as &$element)
                      {
                          $element = new $class($element);
                      }
                      unset($element);        
                      return $children;
                  }
              }
              
              class TreeNodesIterator implements \RecursiveIterator
              {
                  private $nodes;
                  public function __construct(array $nodes)
                  {
                      $this->nodes = new \ArrayIterator($nodes);
                  }
                  public function  getInnerIterator()
                  {
                      return $this->nodes;
                  }
                  public function getChildren()
                  {
                      return new TreeNodesIterator($this->nodes->current()->getChildren());
                  }
                  public function hasChildren()
                  {
                      return $this->nodes->current()->hasChildren();
                  }
                  public function rewind()
                  {
                      $this->nodes->rewind();
                  }
                  public function valid()
                  {
                      return $this->nodes->valid();
                  }   
                  public function current()
                  {
                      return $this->nodes->current();
                  }
                  public function key()
                  {
                      return $this->nodes->key();
                  }
                  public function next()
                  {
                      return $this->nodes->next();
                  }
              }
              
              class RecursiveListIterator extends \RecursiveIteratorIterator
              {
                  private $elements;
                  /**
                   * @var ListDecorator
                   */
                  private $decorator;
                  public function addDecorator(ListDecorator $decorator)
                  {
                      $this->decorator = $decorator;
                  }
                  public function __construct($iterator, $mode = \RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
                  {
                      parent::__construct($iterator, $mode, $flags);
                  }
                  private function event($name)
                  {
                      // event debug code: printf("--- %'.-20s --- (Depth: %d, Element: %d)\n", $name, $this->getDepth(), @$this->elements[$this->getDepth()]);
                      $callback = array($this->decorator, $name);
                      is_callable($callback) && call_user_func($callback);
                  }
                  public function beginElement()
                  {
                      $this->event('beginElement');
                  }
                  public function beginChildren()
                  {
                      $this->event('beginChildren');
                  }
                  public function endChildren()
                  {
                      $this->testEndElement();
                      $this->event('endChildren');
                  }
                  private function testEndElement($depthOffset = 0)
                  {
                      $depth = $this->getDepth() + $depthOffset;      
                      isset($this->elements[$depth]) || $this->elements[$depth] = 0;
                      $this->elements[$depth] && $this->event('endElement');
              
                  }
                  public function nextElement()
                  {
                      $this->testEndElement();
                      $this->event('{nextElement}');
                      $this->event('beginElement');       
                      $this->elements[$this->getDepth()] = 1;
                  } 
                  public function beginIteration()
                  {
                      $this->event('beginIteration');
                  }
                  public function endIteration()
                  {
                      $this->testEndElement();
                      $this->event('endIteration');       
                  }
              }
              
              class ListDecorator
              {
                  private $iterator;
                  public function __construct(RecursiveListIterator $iterator)
                  {
                      $this->iterator = $iterator;
                  }
                  public function inset($add = 0)
                  {
                      return str_repeat('  ', $this->iterator->getDepth()*2+$add);
                  }
                  public function beginElement()
                  {
                      printf("%s<li>\n", $this->inset(1));
                  }
                  public function endElement()
                  {
                      printf("%s</li>\n", $this->inset(1));
                  }
                  public function beginChildren()
                  {
                      printf("%s<ul>\n", $this->inset());
                  }
                  public function endChildren()
                  {
                      printf("%s</ul>\n", $this->inset());
                  }
                  public function beginIteration()
                  {
                      printf("%s<ul>\n", $this->inset());
                  }
                  public function endIteration()
                  {
                      printf("%s</ul>\n", $this->inset());
                  }
              }
              
              
              $root = new TreeNode($tree);
              $it = new TreeNodesIterator(array($root));
              $rit = new RecursiveListIterator($it);
              $decor = new ListDecorator($rit);
              $rit->addDecorator($decor);
              
              foreach($rit as $item)
              {
                  $inset = $decor->inset(2);
                  printf("%s%s\n", $inset, $item->getName());
              }
              

              Outpupt :

              <ul>
                <li>
                  D
                  <ul>
                    <li>
                      G
                      <ul>
                        <li>
                          H
                        </li>
                        <li>
                          F
                        </li>
                      </ul>
                    </li>
                    <li>
                      E
                      <ul>
                        </li>
                        <li>
                          A
                        </li>
                        <li>
                          C
                          <ul>
                            <li>
                              B
                            </li>
                          </ul>
                        </li>
                      </ul>
                    </li>
                  </ul>
                </li>
              </ul>
              

              데모 (PHP 5.2 변형)

              가능한 변형은 모든 RecursiveIterator를 반복하고 발생할 수있는 모든 이벤트에 대해 반복을 제공하는 반복자입니다. foreach 루프 내부의 스위치 / 케이스가 이벤트를 처리 할 수 ​​있습니다.

              관련 항목 :

            • ==============================

              4.음, 먼저 키 - 값 쌍의 직선 배열을 계층 적 배열로 바꿉니다.

              음, 먼저 키 - 값 쌍의 직선 배열을 계층 적 배열로 바꿉니다.

              function convertToHeiarchical(array $input) {
                  $parents = array();
                  $root = array();
                  $children = array();
                  foreach ($input as $item) {
                      $parents[$item['id']] = &$item;
                      if ($item['parent_id']) {
                          if (!isset($children[$item['parent_id']])) {
                              $children[$item['parent_id']] = array();
                          }
                          $children[$item['parent_id']][] = &$item;
                      } else {
                          $root = $item['id'];
                      }
                  }
                  foreach ($parents as $id => &$item) {
                      if (isset($children[$id])) {
                          $item['children'] = $children[$id];
                      } else {
                          $item['children'] = array();
                      }
                  }
                  return $parents[$root];
              }
              

              그러면 parent_id와 id가있는 평면 배열을 계층 적 배열로 변환 할 수 있습니다.

              $item = array(
                  'id' => 'A',
                  'blah' => 'blah',
                  'children' => array(
                      array(
                          'id' => 'B',
                          'blah' => 'blah',
                          'children' => array(
                              array(
                                  'id' => 'C',
                                  'blah' => 'blah',
                                  'children' => array(),
                              ),
                           ),
                          'id' => 'D',
                          'blah' => 'blah',
                          'children' => array(
                              array(
                                  'id' => 'E',
                                  'blah' => 'blah',
                                  'children' => array(),
                              ),
                          ),
                      ),
                  ),
              );
              

              그런 다음 렌더링 기능을 만듭니다.

              function renderItem($item) {
                  $out = "Your OUtput For Each Item Here";
                  $out .= "<ul>";
                  foreach ($item['children'] as $child) {
                      $out .= "<li>".renderItem($child)."</li>";
                  }
                  $out .= "</ul>";
                  return $out;
              }
              
            • ==============================

              5.Alexander-Konstantinov의 솔루션은 처음에는 읽기가 쉽지 않지만 성능 측면에서는 천재성과 기하 급수적으로 더 뛰어나지 만 최고의 해답으로 선정되었습니다.

              Alexander-Konstantinov의 솔루션은 처음에는 읽기가 쉽지 않지만 성능 측면에서는 천재성과 기하 급수적으로 더 뛰어나지 만 최고의 해답으로 선정되었습니다.

              감사의 말,이 게시물에 제시된 2 가지 솔루션을 비교하기 위해 벤치 마크를 작성했습니다.

              나는 변환해야만했던 6 레벨의 @ 250k 플랫 트리를 가지고 있었고 그렇게하는 더 좋은 방법을 찾고 재귀 반복을 피했습니다.

              재귀 대 참조 :

              // Generate a 6 level flat tree
              $root = null;
              $lvl1 = 13;
              $lvl2 = 11;
              $lvl3 = 7;
              $lvl4 = 5;
              $lvl5 = 3;
              $lvl6 = 1;    
              $flatTree = [];
              for ($i = 1; $i <= 450000; $i++) {
                  if ($i % 3 == 0)  { $lvl5 = $i; $flatTree[$lvl6] = $lvl5; continue; }
                  if ($i % 5 == 0)  { $lvl4 = $i; $flatTree[$lvl5] = $lvl4; continue; }
                  if ($i % 7 == 0)  { $lvl3 = $i; $flatTree[$lvl3] = $lvl2; continue; }
                  if ($i % 11 == 0) { $lvl2 = $i; $flatTree[$lvl2] = $lvl1; continue; }
                  if ($i % 13 == 0) { $lvl1 = $i; $flatTree[$lvl1] = $root; continue; }
                  $lvl6 = $i;
              }
              
              echo 'Array count: ', count($flatTree), PHP_EOL;
              
              // Reference function
              function treeByReference($flatTree)
              {
                  $flat = [];
                  $tree = [];
              
                  foreach ($flatTree as $child => $parent) {
                      if (!isset($flat[$child])) {
                          $flat[$child] = [];
                      }
                      if (!empty($parent)) {
                          $flat[$parent][$child] =& $flat[$child];
                      } else {
                          $tree[$child] =& $flat[$child];
                      }
                  }
              
                  return $tree;
              }
              
              // Recursion function
              function treeByRecursion($flatTree, $root = null)
              {
                  $return = [];
                  foreach($flatTree as $child => $parent) {
                      if ($parent == $root) {
                          unset($flatTree[$child]);
                          $return[$child] = treeByRecursion($flatTree, $child);
                      }
                  }
                  return $return ?: [];
              }
              
              // Benchmark reference
              $t1 = microtime(true);
              $tree = treeByReference($flatTree);
              echo 'Reference: ', (microtime(true) - $t1), PHP_EOL;
              
              // Benchmark recursion
              $t2 = microtime(true);
              $tree = treeByRecursion($flatTree);
              echo 'Recursion: ', (microtime(true) - $t2), PHP_EOL;
              

              출력 자체에 대해 말하고 있습니다 :

              Array count: 255493
              Reference: 0.3259289264679 (less than 0.4s)
              Recursion: 6604.9865279198 (almost 2h)
              
            • ==============================

              6.UL과 LI를 파싱하려면 다음과 같이됩니다.

              UL과 LI를 파싱하려면 다음과 같이됩니다.

              $array = array (
                  'H' => 'G'
                  'F' => 'G'
                  'G' => 'D'
                  'E' => 'D'
                  'A' => 'E'
                  'B' => 'C'
                  'C' => 'E'
                  'D' => 'NULL'
              );
              
              
              recurse_uls ($array, 'NULL');
              
              function recurse_uls ($array, $parent)
              {
                  echo '<ul>';
                  foreach ($array as $c => $p)  {
                      if ($p != $parent) continue;
                      echo '<li>'.$c.'</li>';
                      recurse_uls ($array, $c);
                  }
                  echo '</ul>';
              }
              

              하지만 배열을 반복적으로 반복 할 필요가없는 솔루션을보고 싶습니다 ...

            • ==============================

              7.다음은 내가 생각해 낸 것입니다.

              다음은 내가 생각해 낸 것입니다.

              $arr = array(
                          'H' => 'G',
                          'F' => 'G',
                          'G' => 'D',
                          'E' => 'D',
                          'A' => 'E',
                          'B' => 'C',
                          'C' => 'E',
                          'D' => null );
              
                  $nested = parentChild($arr);
                  print_r($nested);
              
                  function parentChild(&$arr, $parent = false) {
                    if( !$parent) { //initial call
                       $rootKey = array_search( null, $arr);
                       return array($rootKey => parentChild($arr, $rootKey));
                    }else { // recursing through
                      $keys = array_keys($arr, $parent);
                      $piece = array();
                      if($keys) { // found children, so handle them
                        if( !is_array($keys) ) { // only one child
                          $piece = parentChild($arr, $keys);
                         }else{ // multiple children
                           foreach( $keys as $key ){
                             $piece[$key] = parentChild($arr, $key);
                           }
                         }
                      }else {
                         return $parent; //return the main tag (no kids)
                      }
                      return $piece; // return the array built via recursion
                    }
                  }
              

              출력 :

              Array
              (
                  [D] => Array
                      (
                          [G] => Array
                              (
                                  [H] => H
                                  [F] => F
                              )
              
                          [E] => Array
                              (
                                  [A] => A
                                  [C] => Array
                                      (
                                          [B] => B
                                      )    
                              )    
                      )    
              )
              
            • ==============================

              8.동적 트리보기 및 메뉴를 만드는 방법

              동적 트리보기 및 메뉴를 만드는 방법

              1 단계 : 먼저 우리는 mysql 데이터베이스에 treeview 테이블을 생성합니다. 이 테이블에는 4 개의 column.id가 포함되어 있으며 id는 작업 ID이며 name은 작업 이름입니다.

              -
              -- Table structure for table `treeview_items`
              --
              
              CREATE TABLE IF NOT EXISTS `treeview_items` (
                `id` int(11) NOT NULL AUTO_INCREMENT,
                `name` varchar(200) NOT NULL,
                `title` varchar(200) NOT NULL,
                `parent_id` varchar(11) NOT NULL,
                PRIMARY KEY (`id`)
              ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
              
              --
              -- Dumping data for table `treeview_items`
              --
              
              INSERT INTO `treeview_items` (`id`, `name`, `title`, `parent_id`) VALUES
              (1, 'task1', 'task1title', '2'),
              (2, 'task2', 'task2title', '0'),
              (3, 'task3', 'task1title3', '0'),
              (4, 'task4', 'task2title4', '3'),
              (5, 'task4', 'task1title4', '3'),
              (6, 'task5', 'task2title5', '5');
              

              2 단계 : 트리 뷰 재귀 적 방법 현재 작업 ID가 이전 작업 ID보다 큰 경우 재귀 호출 트리 createTreeView () 메서드를 만들었습니다.

              function createTreeView($array, $currentParent, $currLevel = 0, $prevLevel = -1) {
              
              foreach ($array as $categoryId => $category) {
              
              if ($currentParent == $category['parent_id']) {                       
                  if ($currLevel > $prevLevel) echo " <ol class='tree'> "; 
              
                  if ($currLevel == $prevLevel) echo " </li> ";
              
                  echo '<li> <label for="subfolder2">'.$category['name'].'</label> <input type="checkbox" name="subfolder2"/>';
              
                  if ($currLevel > $prevLevel) { $prevLevel = $currLevel; }
              
                  $currLevel++; 
              
                  createTreeView ($array, $categoryId, $currLevel, $prevLevel);
              
                  $currLevel--;               
                  }   
              
              }
              
              if ($currLevel == $prevLevel) echo " </li>  </ol> ";
              
              }
              

              3 단계 : 트리 뷰를 표시 할 색인 파일을 만듭니다. 이것은 treeview 예제의 주요 파일입니다. 여기서는 필수 매개 변수와 함께 createTreeView () 메소드를 호출합니다.

               <body>
              <link rel="stylesheet" type="text/css" href="_styles.css" media="screen">
              <?php
              mysql_connect('localhost', 'root');
              mysql_select_db('test');
              
              
              $qry="SELECT * FROM treeview_items";
              $result=mysql_query($qry);
              
              
              $arrayCategories = array();
              
              while($row = mysql_fetch_assoc($result)){ 
               $arrayCategories[$row['id']] = array("parent_id" => $row['parent_id'], "name" =>                       
               $row['name']);   
                }
              ?>
              <div id="content" class="general-style1">
              <?php
              if(mysql_num_rows($result)!=0)
              {
              ?>
              <?php 
              
              createTreeView($arrayCategories, 0); ?>
              <?php
              }
              ?>
              
              </div>
              </body>
              

              4 단계 : CSS 파일 style.css 만들기 여기에 우리는 모든 CSS 관련 클래스를 작성합니다. 현재 트리 목록을 작성하는 순서 목록을 사용하고 있습니다. 여기에서 이미지 경로를 변경할 수도 있습니다.

              img { border: none; }
              input, select, textarea, th, td { font-size: 1em; }
              
              /* CSS Tree menu styles */
              ol.tree
              {
                  padding: 0 0 0 30px;
                  width: 300px;
              }
                  li 
                  { 
                      position: relative; 
                      margin-left: -15px;
                      list-style: none;
                  }
                  li.file
                  {
                      margin-left: -1px !important;
                  }
                      li.file a
                      {
                          background: url(document.png) 0 0 no-repeat;
                          color: #fff;
                          padding-left: 21px;
                          text-decoration: none;
                          display: block;
                      }
                      li.file a[href *= '.pdf']   { background: url(document.png) 0 0 no-repeat; }
                      li.file a[href *= '.html']  { background: url(document.png) 0 0 no-repeat; }
                      li.file a[href $= '.css']   { background: url(document.png) 0 0 no-repeat; }
                      li.file a[href $= '.js']        { background: url(document.png) 0 0 no-repeat; }
                  li input
                  {
                      position: absolute;
                      left: 0;
                      margin-left: 0;
                      opacity: 0;
                      z-index: 2;
                      cursor: pointer;
                      height: 1em;
                      width: 1em;
                      top: 0;
                  }
                      li input + ol
                      {
                          background: url(toggle-small-expand.png) 40px 0 no-repeat;
                          margin: -0.938em 0 0 -44px; /* 15px */
                          height: 1em;
                      }
                      li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }
                  li label
                  {
                      background: url(folder-horizontal.png) 15px 1px no-repeat;
                      cursor: pointer;
                      display: block;
                      padding-left: 37px;
                  }
              
                  li input:checked + ol
                  {
                      background: url(toggle-small.png) 40px 5px no-repeat;
                      margin: -1.25em 0 0 -44px; /* 20px */
                      padding: 1.563em 0 0 80px;
                      height: auto;
                  }
                      li input:checked + ol > li { display: block; margin: 0 0 0.125em;  /* 2px */}
                      li input:checked + ol > li:last-child { margin: 0 0 0.063em; /* 1px */ }
              

              자세한 내용은

            from https://stackoverflow.com/questions/2915748/convert-a-series-of-parent-child-relationships-into-a-hierarchical-tree by cc-by-sa and MIT license