首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Yii2中遍历层次树邻接表模型

在Yii2中遍历层次树邻接表模型
EN

Stack Overflow用户
提问于 2017-08-18 13:37:36
回答 1查看 673关注 0票数 1

我被困在一个逻辑上,我不能理解它是如何完成的,并遍历列表。

实际上,我正在创建一个类别列表,该列表将在创建产品时进一步使用。我希望类别列表应该是父节点及其子节点的形式,就像邻接表模型一样。

数据库:

代码语言:javascript
复制
id        categoryname        parent [id is the foreign key for the parent]
 1           a                  1
 2           b                  2
 3           c                  2
 4           e                  2
 5           f                  3
 6           g                  4

在yii2中使用ActiveQuery获取详细信息:

代码语言:javascript
复制
$rows = Category::find()
             ->asArray()
             ->all();

$rows数组包含如下形式的数据

代码语言:javascript
复制
Array
(
  [0] => Array
    (
        [id] => 1
        [categoryname] => a
        [parent] => 1 
   )

  [1] => Array
    (
        [id] => 2
        [categoryname] => b
        [parent] =>2
    )

  [2] => Array
    (
        [id] => 3
        [categoryname] => c
        [parent] => 2
    )
)
And so on...

我希望期望的输出应该是这样的列表形式

代码语言:javascript
复制
[ 
  [ 
    'id' => 1, 
    'categoryname' => 'a'
  ], 
  [ 
    'id' => 2, 
    'categoryname' => 'b'
  ], 
  [ 
    'id' => 3,
    'categoryname' => 'b > c'
  ], 
  [ 
    'id' => 4, 
    'categoryname' => 'b>c>f' 
  ]
 ] 

我尝试过:当我从表中获取行并将它们存储在关联数组中时。每个分支节点的子ids存储在另一个关联数组中。

代码语言:javascript
复制
foreach ($rows as $row){
        $id = $row["id"];
        $parent_id = $row["parent"] === NULL ? "NULL" : $row["parent"];
        $data[$id] = $row;
        $index[$parent_id][] = $id;
    }
    function display_child_nodes($parent_id, $level,$data,$index)
    {

        $parent_id = $parent_id === NULL ? "NULL" : $parent_id;
        if (isset($index[$parent_id])) {
            foreach ($index[$parent_id] as $id) {
                $result['id'] = $data[$id]['id'];
                $result['name'] = $data[$id]['categoryname'];
                $result['level'] = $level;
                echo str_repeat("-", $level) . $data[$id]["categoryname"] . "\n";
                display_child_nodes($id, $level + 1,$data,$index);
            }

        }
    }
    display_child_nodes(NULL, 0,$data,$index);

为了得到结果,我遵循了这个reference,但是我不能得到想要的输出。

我已经解决了堆栈溢出问题,但没有一个对我有用。因此,任何人都可以帮助在高级欣赏。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-18 17:19:10

为此,您可以使用Iterators。让我们扩展RecursiveArrayIterator并调用新迭代器AdjacencyListIterator

代码语言:javascript
复制
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']);
            });

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

    private $children;

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

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

        return false;
    }

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

顺便说一句,请注意,对于顶级父母来说,parent应该是null (而不是id)。

有了这个迭代器,你就可以生成这样的路径:

代码语言:javascript
复制
$iterator = new RecursiveIteratorIterator(
    new AdjacencyListIterator($rows),
    RecursiveIteratorIterator::SELF_FIRST
);

$path = [];
foreach ($iterator as $node) {
    $depth = $iterator->getDepth();
    $path[$depth] = $node['categoryname'];

    echo implode(' > ', array_slice($path, 0, $depth + 1)), PHP_EOL;
}

这是working demo

这种方法可能比自定义递归函数慢一点。但它实际上更灵活。通过仅更改遍历模式,您可以仅获取叶,例如:

代码语言:javascript
复制
$iterator = new RecursiveIteratorIterator(
    new AdjacencyListIterator($rows)
);

foreach ($iterator as $leaf) {
    echo $leaf['categoryname'], PHP_EOL;
}

这种情况与以前的不同之处在于,我们将RecursiveIteratorIterator$mode设置为默认的RecursiveIteratorIterator::LEAVES_ONLY

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45749208

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档