如何将扁平数组排序成多维树形结构

4

I have a table like

id    catagory      suboff

1     software       0
2     programming    1
3     Testing        1
4     Designing      1
5     Hospital       0
6     Doctor         5
7     Nurses         5
9     Teaching       0
10    php programming 2
11    .net programming 2

如何编写一段代码,根据以下的子偏移量获取所有这些信息并存储在一个多维数组中:
-software
--programming
---php programming
--- .net programming
--testing
--designing
-hospital 
--doctor
--nurses
-teaching

你的意思是什么?数据是从哪里来的?是从数据库、文件还是硬编码中获取的? - San
10个回答

3

假设您的数据库引擎是MySQL:

// We'll need two arrays for this
$temp = $result = array();

// Get the data from the DB
$table = mysql_query("SELECT * FROM table");

// Put it into one dimensional array with the row id as the index
while ($row = mysql_fetch_assoc($table)) {
  $temp[$row['id']] = $row;
}

// Loop the 1D array and create the multi-dimensional array
for ($i = 1; isset($temp[$i]); $i++) {
  if ($temp[$i]['suboff'] > 0) {
    // This row has a parent
    if (isset($temp[$temp[$i]['suboff']])) {
      // The parent row exists, add this row to the 'children' key of the parent
      $temp[$temp[$i]['suboff']]['children'][] =& $temp[$i];
    } else {
      // The parent row doesn't exist - handle that case here
      // For the purposes of this example, we'll treat it as a root node
      $result[] =& $temp[$i];
    }
  } else {
    // This row is a root node
    $result[] =& $temp[$i];
  }
}

// unset the 1D array
unset($temp);

// Here is the result
print_r($result);

像这样的工作,请使用引用


1
演示:http://ideone.com/vk4po
$array = array(
array('1','software','0'),
array('2','programming','1'),
array('3','Testing','1'),
array('4','Designing','1'),
array('5','Hospital','0'),
array('6','Doctor','5'),
array('7','Nurses','5'),
array('9','Teaching','0'),
array('10','php programming','2'),
array('11','.net programming','2')
);

function menu_sort($results, $master = 0)
{

    $open = array();
    $return = NULL;

    foreach($results as $result)
    {
        if($result[2] == $master){

            if(!$open){
                $return .= '<ul>';
                $open = true;
            }

            $return .= '<li>'.$result[1];

            $return .= menu_sort($results, $result[0]);
            $return .= '</li>';

        }
    }

    if($open)
        $return .= '</ul>';

    return $return;

}

echo menu_sort($array);

结果...

software
    programming
        php programming
        .net programming
    Testing
    Designing
Hospital
    Doctor
    Nurses
Teaching

4
他要求一个数组,而不是一个 <ul /> - middus

1

这个类将一个扁平的分类数组转换成一个结构化的树形数组:

<?php

/**
 * Creates a structured tree out of a flat category list
 */
class CategoryTree {

  /**
   *
   * @var array
   */
  protected $categories = array();

  /**
   *
   * @var array
   */
  protected $tree = array();

  /**
   * Default constructor
   * @param array $categories 
   */
  function __construct(array $categories) {
    $this->categories = $categories;
  }

  /**
   * Process a subtree
   * @param array $categories
   * @param integer $parentId
   * @return array 
   */
  protected function getSubtree(array $categories, $parentId = 0) {
    $tree = array();

    foreach($categories as $category) {
      if($category['suboff'] == $parentId) {
        $tree[$category['id']] = $category;
        $tree[$category['id']]['children'] = $this->getSubtree($categories, $category['id']);
      }
    }

    return $tree;
  }

  /**
   * Get the category tree as structured array
   * @return array 
   */
  public function getTree() {
    if(empty($this->tree)) {
      $this->tree = $this->getSubtree($this->categories, 0);
    }
    return $this->tree;
  }

  /**
   * Get the category tree as string representation
   * @return string
   */
  public function __toString() {
    return "<pre>" . print_r($this->getTree(), true) . "</pre>";
  }

}


// Now, use the class with the givven data:

$categories = array(
  array(
    'id' => 1,
    'category' => 'software',
    'suboff' => 0
  ),
  array(
    'id' => 2,
    'category' => 'programming',
    'suboff' => 1
  ),
  array(
    'id' => 3,
    'category' => 'Testing',
    'suboff' => 1
  ),
  array(
    'id' => 4,
    'category' => 'Designing',
    'suboff' => 1
  ),
  array(
    'id' => 5,
    'category' => 'Hospital',
    'suboff' => 0
  ),
  array(
    'id' => 6,
    'category' => 'Doctor',
    'suboff' => 5
  ),
  array(
    'id' => 7,
    'category' => 'Nurses',
    'suboff' => 5
  ),
  array(
    'id' => 9,
    'category' => 'Teaching',
    'suboff' => 0
  ),
  array(
    'id' => 10,
    'category' => 'php programming',
    'suboff' => 2
  ),
  array(
    'id' => 11,
    'category' => '.net programming',
    'suboff' => 2
  )
);

$myTree = new CategoryTree($categories);
echo $myTree;

?>

1
我会这样做:
  1. 首先,您需要解析此表。我假设您可以自己完成;如果不行,请搜索“正则表达式”,它们是您的朋友。

  2. 您正在使用的数据结构是经典的。您将需要两个数组来处理它。第一个是节点数组$nodes,其中键是节点ID,值是节点名称,第二个是链接数组$links,其中每个键是父节点,每个值是子节点的数组(对于每个元素,$links[$id][] = $suboff就足够了)。

  3. 现在,您必须递归地遍历您拥有的树。您可以引入一个函数,其签名如下:

    function print_node( $nodeID, $level = 1 )
    

    此函数应打印节点本身(存储在$nodes中的信息),并使用$level填充破折号调用自身以呈现所有子节点。它们将依次呈现所有子节点的子节点等。您只需为顶级节点调用此函数即可。


我猜他在谈论一个数据库表。 - middus

1
这是我刚为我的应用程序编写的内容,它运行得非常好 :)
$array = [
    'i' => ['key' => 'i', 'name' => 'php programming', 'parent' => 'b'], 
    'g' => ['key' => 'g', 'name' => 'Nurses', 'parent' => 'e'],
    'j' => ['key' => 'j', 'name' => '.net programming', 'parent' => 'b'], 
    'b' => ['key' => 'b', 'name' => 'programming', 'parent' => 'a'],
    'a' => ['key' => 'a', 'name' => 'software', 'parent' => 'asd'],
    'c' => ['key' => 'c', 'name' => 'Testing', 'parent' => 'a'], 
    'd' => ['key' => 'd', 'name' => 'Designing', 'parent' => 'a'], 
    'e' => ['key' => 'e', 'name' => 'Hospital', 'parent' => 'asd'],  
    'f' => ['key' => 'f', 'name' => 'Doctor', 'parent' => 'e'], 
    'h' => ['key' => 'h', 'name' => 'Teaching'],  
];

function getAsTree(array &$array)
{
    foreach ($array as $key => $item) {
        if (isset($item['parent']) && isset($array[$item['parent']])) {
            $array[$item['parent']]['children'][] = $item;
            unset($array[$key]);
            return getAsTree($array);
        }
    }

    return $array;
}

这里是结果:

--- a: software
------ b: programming
--------- i: php programming
--------- j: .net programming
------ c: Testing
------ d: Designing
--- e: Hospital
------ g: Nurses
------ f: Doctor
--- h: Teaching

0

在 PHP 中,当我从数据库获取数据时:

"SELECT* FROM Table WHERE suboff LIKE 0"
foreach(item..)
   "SELECT* FROM Table WHERE suboff LIKE item.ID"
       foreach(item2..)
          $result[item][item2]

这样做非常低效,因为你需要进行大量的查询。最好只查询一次数据,让 PHP 在内存中完成操作(请参见我的答案)。 - middus
好的.. 我在上面用了这个菜单,数据不是很多。但你说得对,我的解决方案不太可扩展。 - San

0

这里有一个不同的方法,应该非常容易理解。它要求您按suboff排序表格,即

SELECT * FROM table ORDER BY suboff

假设结果存储在$table中,您可以使用这个非常简洁的PHP代码:
// this will hold the result
$tree = array();
// used to find an entry using its id
$lookup = array();
foreach($table as $row){
  if($row['suboff'] === 0){
    // this has no parent, add it at base level
    $tree[$row['category']] = array();
    // store a reference
    $lookup[$row['id']] =& $tree[$row['category']];
  }else{
    // find the right parent, add the category
    $lookup[$row['suboff']][$row['category']] = array();
    // store a reference
    $lookup[$row['id']] =& $lookup[$row['suboff']][$row['category']];
  }
}

0

这个解决方案对我来说很好用。

$array = array(
    array('1','software','0'),
    array('2','programming','1'),
    array('3','Testing','1'),
    array('4','Designing','1'),
    array('5','Hospital','0'),
    array('6','Doctor','5'),
    array('7','Nurses','5'),
    array('9','Teaching','0'),
    array('10','php programming','2'),
    array('11','.net programming','2')
);

$newArray = getTree($array);

function getTree( $rows, $suboff = 0) {

    $return = array();

    foreach($rows as $row) {

        if($row[2] == $suboff){

            $newrow = $row;

            $subs = $this->getTree($rows, $row[0]);

            if ( !empty($subs) ) {
                $newrow['subs'] = $subs;
            }

            $return[] = $newrow;

        }
    }

    return $return;

}

0

我认为逻辑是这样的:

  1. 获取所有根元素(软件、医院等)
  2. 对于每个根元素,获取其子元素(例如,对于软件,你会获取编程、测试和设计)
  3. 将子元素作为子数组添加
  4. 递归循环刚刚添加的子数组

0
你需要将整个表格读入内存,并将其转换为一棵树,其中每个节点都可以用其对应的ID号进行标识。然后对树进行先序遍历以打印输出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接