遍历数组作为PHP中的树

时间:2011-06-16 13:08:15

标签: php mysql

我有一个描述层次结构的db表。这是结构

 id | pid | uid 
  1    5     2
  2    2     3
  3    2     4
  4    2     6
  5    3     7

在树形结构中它会看起来像这样。这只是一个例子,它们可能是更多的节点。

         2 
      /  |  \
     3   4   6
    /      
   7 

所以在php和mysql中我获取所有数据并将其保存到数组中。

我想遍历该数组以确定例如特定级别的id的数量,我希望能够从一个级别检索所有节点。

我怎么能在PHP中这样做?

修改

这就是我创建数组的方式:

foreach ( $resultSet as $row ) {
    $entry = array();
    $entry['id'] = $row->id;
    $entry['uid'] = $row->uid;
    $entry['rid'] = $row->rid;
    $entry['date'] = $row->date;
    $entries [] = $entry;
}

这就是我现在使用答案

创建树的方法
$tree = array();
foreach($entries as $key){
   $this->adj_tree($tree, $key);
}
return $tree;

但是当我打印$ tree

时,我得到一些奇怪的输出
Array ( [24] => Array ( [id] => 6 [uid] => 24 [rid] => 83 [date] => 2011-06-15
17:54:14 ) [] => Array ( [_children] => Array ( [0] => Array ( [id] => 6 [uid] => 24 
[rid] => 83 [date] => 2011-06-15 17:54:14 ) [1] => Array ( [id] => 6 [uid] => 24 [rid] =>
83 [date] => 2011-06-15 17:54:14 ) ) ) ) 

但实际上应该有一个父母的uid为24,其中两个孩子有82和83

3 个答案:

答案 0 :(得分:4)

你没有说你是如何使用你的桌子的,但我想这是一个商店类别树,或类似的东西,即一个不需要任何复杂存储的小数据集。您可以立即读取整个表格并使用php动态构建树形结构。它就像这样

function adj_tree(&$tree, $item) {
    $i = $item['uid'];
    $p = $item['pid'];
    $tree[$i] = isset($tree[$i]) ? $item + $tree[$i] : $item;
    $tree[$p]['_children'][] = &$tree[$i];
}

示例:

$tree = array();
$rs = my_query("SELECT * FROM categories");
while($row = my_fetch($rs))
    adj_tree($tree, $row);

最后,你得到一个项目数组,每个项目包含'_children'子数组,而这些子数组又包含对其他项的引用(或为空)。

完整示例,包含问题数据

$entries = array(
  array('id' => 1, 'pid' => 5, 'uid' => 2),
  array('id' => 2, 'pid' => 2, 'uid' => 3),
  array('id' => 3, 'pid' => 2, 'uid' => 4),
  array('id' => 4, 'pid' => 2, 'uid' => 6),
  array('id' => 5, 'pid' => 3, 'uid' => 7),
);

$tree = array();
foreach($entries as $row)
    adj_tree($tree, $row);

function print_tree($node, $indent) {
    echo str_repeat('...', $indent) . $node['uid'], "<br>\n";
    if(isset($node['_children']))
        foreach($node['_children'] as $child)
            print_tree($child, $indent + 1);
}

print_tree($tree[2], 0);

答案 1 :(得分:2)

与任何其他面向对象语言相同 - 创建自己的树和节点类,以满足您的需求。

另一种方法是使用数组创建树(在PHP数组中是关联的,可以嵌套)

我同意Vinicius Kamakura - 如果数据集明显很大,则不应将数据加载到PHP。

答案 2 :(得分:0)

我已根据user187291 answer构建了一个类。

class Tree
{
    protected $tree;
    protected $rootid;

    public function __construct($entries)
    {
        $this->tree = array();
        $this->rootid = PHP_INT_MAX;

        /* Build tree under each node */
        foreach($entries as $node)
            $this->buildTree($this->tree, $node);
    }


    /* Build tree */
    protected function buildTree(&$tree, $node) 
    {
        $i = $node['id'];
        $p = $node['pid'];
        $this->rootid = min($this->rootid, $p);
        $tree[$i] = isset($tree[$i]) ? $node + $tree[$i] : $node;
        $tree[$p]['_children'][] = &$tree[$i];
    }


    /* Print tree */
    public function printTree() 
    {
        $this->printSubtree($this->tree[$this->rootid]);
    }


    /* Print subtree under given node */
    protected function printSubtree($node, $depth=0) 
    {
        /* Root node doesn't have id */
        if(isset($node['id']))
        {
            echo str_repeat('...', $depth) . $node['id'], "<br>\n";
        }

        /* Explore children */
        if(isset($node['_children']))
        {
            foreach($node['_children'] as $child)
                $this->printSubtree($child, $depth + 1);
        }
    }


    /* Destroy instance data */
    public function __destruct() 
    {
        $this->tree = null;
    }
}

用法示例

$entries = array(
  array('pid' => 2, 'id' => 3),
  array('pid' => 0, 'id' => 2),
  array('pid' => 3, 'id' => 7),
  array('pid' => 2, 'id' => 4),
  array('pid' => 2, 'id' => 6),
  array('pid' => 3, 'id' => 8),
  array('pid' => 0, 'id' => 9),
);

$tree = new Tree($entries);
$tree->printTree();

希望它有所帮助。当然,您可以向“条目”元素添加字段,只需记住如果要打印它们,请更改“printSubtree”方法。

备注: 此类假定节点具有“id”和“pid”的数值,父节点的“id”低于其子节点(在树结构中很常见)。