单维数组中的PHP父/子迭代

时间:2017-09-08 19:00:55

标签: php arrays

我对如何解决这个问题感到有点失落,我怀疑foreach不是正确的答案,我知道array_walk()和{{1}的存在但是,我没有使用任何一个的实际经验,所以我可以在正确的方向上做一点指针。 (如果它对答案有任何影响,我正在使用PHP 7.1.9。)

来源数据

我有一个包含父/子对象树的单维数组。您可以假设树具有未知和可变的嵌套深度。一个基本示例如下所示:

RecursiveArrayIterator

所需的输出

最终目标是输出HTML列表(即$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); ),每个父级一个列表。通过嵌套<ul><li></li></ul>标记实现嵌套。所以对于我上面的例子:

<ul>

2 个答案:

答案 0 :(得分:1)

我可以建议以OOP方式执行此操作吗? 我创建了一个包含属性和子列表的对象。如果您愿意,还可以添加从子项到其父项的链接,如此示例

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

使用这种结构,使用foreach迭代它应该非常简单。

答案 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;
    }
}

拥有这两个类,你可以像这样迭代你的树:

$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仅用于演示目的,应在现实代码中删除。