2017-09-08 8 views
0

私はこれにどのように接近するかについて少し損失がありますが、私はforeachが正しい答えではないと思っています。私はarray_walk()RecursiveArrayIteratorの存在を知っています。しかし、私はどちらかを使用して実際の経験がないので、私は正しい方向に少しのポインタで行うことができます。 (私は答えに何か違いがあればPHP 7.1.9で作業しています)。1次元配列の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>)、親ごとに1つのリストにあります。 <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人だけですか? –

+1

$ sampleTree = '$ sampleTree = array($ sampleParent、$ sampleChildD1、$ sampleChildD2);'配列または多次元配列を持つ配列になります。これは、sampleTreeの処理/解析中に、1次元配列を処理していないことを明確にするために、問題を解決するのに役立つものではありません。 –

答えて

1

あなたはRecursiveArrayIteratorを拡張することができます。

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でツリーを飾るために元を拡張することができます

持つ
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; 
    } 
} 

この2つのクラスでは、次のようにツリーを繰り返すことができます。

$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を使用して、それを反復します。