2017-09-08 2 views
0

나는 이것에 접근하는 방법에 관해서는 약간의 손실에있다, 나는 foreach이 맞는 대답이 아니며 나는 array_walk()RecursiveArrayIterator의 존재를 알고있다. 그러나 나는 실제 사용 경험이 없기 때문에 올바른 방향으로 약간의 포인터로 할 수 있습니다. (PHP 7.1.9에서 답을 얻는다면 어떤 차이가 있습니다).PHP 부모/자식 반복에서

소스 데이터

나는 개체의 상위/하위 트리를 포함하는 단일 차원 배열을 가지고있다. 트리에 알려지지 않은 변수 중첩 깊이가 있다고 가정 할 수 있습니다. 기본적인 예는 다음과 같습니다

$sampleParent=array("id"=>101,"level"=>1,"parent_id"=>1,"name"=>"parent","otherparam"=>"bar"); 
$sampleChildD1=array("id"=>234,"level"=>2,"parent_id"=>101,"name"=>"level1","otherparam"=>"bar"); 
$sampleChildD2=array("id"=>499,"level"=>3,"parent_id"=>234,"name"=>"level2","otherparam"=>"bar"); 
$sampleTree=array($sampleParent,$sampleChildD1,$sampleChildD2); 

원하는 출력

궁극적 인 목표는 출력 HTML 목록에 (즉 <ul><li></li></ul>), 부모 당 하나 개의 목록입니다. <ul> 태그를 중첩하여 어린이의 중첩을 달성했습니다. 그래서 위의 예를 들어 :

<ul> 
<li> 
<a href="#">parent</a> 
</li> 
    <ul> 
    <li> 
    <a href="#">level1</a> 
     <ul> 
     <li> 
     <a href="#">level2</a> 
     </li> 
     </ul> 
    </li> 
    </ul> 
</ul> 
+0

지금까지 해보신 것은 무엇입니까? 단일 차원 배열에 트리를 저장하는 방법은 무엇입니까? 부모 한 명당 항상 한 명입니까? –

+1

$ sampleTree를 할 때 $ sampleTree = array ($ sampleParent, $ sampleChildD1, $ sampleChildD2); ' 배열 또는 다차원 배열이있는 배열이됩니다. 이것은 sampleTree를 처리/분석하는 동안 더 이상 단일 차원 배열을 처리하지 않는다는 것을 명확히하기 위해 문제를 해결하는 데 도움이되지 않습니다. –

답변

1

당신은 RecursiveArrayIterator 확장 할 수 있습니다

class UlRecursiveIteratorIterator extends RecursiveIteratorIterator 
{ 
    public function beginIteration() 
    { 
     echo '<ul>', PHP_EOL; 
    } 

    public function endIteration() 
    { 
     echo '</ul>', PHP_EOL; 
    } 

    public function beginChildren() 
    { 
     echo str_repeat("\t", $this->getDepth()), '<ul>', PHP_EOL; 
    } 

    public function endChildren() 
    { 
     echo str_repeat("\t", $this->getDepth()), '</ul>', PHP_EOL; 
     echo str_repeat("\t", $this->getDepth()), '</li>', PHP_EOL; 
    } 
} 

갖는 이 두 클래스는 다음과 같이 트리를 반복 할 수 있습니다.

$iterator = new UlRecursiveIteratorIterator(
    new AdjacencyListIterator($sampleTree), 
    RecursiveIteratorIterator::SELF_FIRST 
); 

foreach ($iterator as $leaf) { 
    echo str_repeat("\t", $iterator->getDepth() + 1); 
    echo '<li>', '<a href="#">', $leaf['name'], '</a>'; 
    echo $iterator->hasChildren() ? '' : '</li>', PHP_EOL; 
} 

여기에 working demo입니다.

여기서 str_repeatPHP_EOL은 프레젠테이션 목적으로 만 사용되었으며 실제 코드에서는 제거해야합니다.

1

내가 이것을 OOP 방식으로 제안하겠습니까? 속성 및 자식 목록을 사용하여 개체를 만들 수 있습니다. 당신이 좋아하는 경우에, 당신은 또한이 구성에이 샘플

class TreeNode { 
    // string 
    public $name; 
    // integer 
    public $id; 
    // TreeNode 
    public $parent; 
    // TreeNode[] 
    public $children; 
} 

같이, 부모에 자식에서 링크를 추가 할 수 있습니다, 그것은 매우 정직해야 foreach 문을 사용하여 반복.

class AdjacencyListIterator extends RecursiveArrayIterator 
{ 
    private $adjacencyList; 

    public function __construct(
     array $adjacencyList, 
     array $array = null, 
     $flags = 0 
    ) { 
     $this->adjacencyList = $adjacencyList; 

     $array = !is_null($array) 
      ? $array 
      : array_filter($adjacencyList, function ($node) { 
       return is_null($node['parent_id']); 
      }); 

     parent::__construct($array, $flags); 
    } 

    private $children; 

    public function hasChildren() 
    { 
     $children = array_filter($this->adjacencyList, function ($node) { 
      return $node['parent_id'] === $this->current()['id']; 
     }); 

     if (!empty($children)) { 
      $this->children = $children; 
      return true; 
     } 

     return false; 
    } 

    public function getChildren() 
    { 
     return new static($this->adjacencyList, $this->children); 
    } 
} 

이 그럼 당신은 RecursiveIteratorIterator로이 반복자를 통과하거나 다소 반 자동으로 HTML과 트리 장식 구를 확장 할 수 있습니다 :