七零部落格
思则大道至简,疑则谜团重重!
思则大道至简,疑则谜团重重!
我们知道很多开源软件的无限分类都是采用递归的算法,但是我们知道递归即浪费时间,又浪费空间(内存),实践中,我们一般会在model中查询出格式化成主键值对应数据的形式,因而我们可以直接用这样的数据,就少了一层循环。代码也非常简洁。
先来看看分类方法:arr.php
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?php
/**
* 方法一:
* 此方法由@Tonton 提供
* @form http://levi.cg.am
* @date 2012-12-12
*/
function genTree5(Array $items) {
foreach ($items as $item)
$items[$item['pid']]['son'][$item['id']] = &$items[$item['id']];
return isset($items[0]['son']) ? $items[0]['son'] : array();
}
/**
* 方法二:将数据格式化成树形结构
* @author Xuefen.Tong
* @form http://levi.cg.am
* @param array $items
* @return array
*/
function genTree9(Array $items) {
$tree = array(); //格式化好的树
foreach ($items as $item)
if (isset($items[$item['pid']]))
$items[$item['pid']]['son'][] = &$items[$item['id']];
else
$tree[] = &$items[$item['id']];
return $tree;
}
|
试着输出看看ex1.php:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<?php
include 'arr.php';
$items = array(
1 => array('id' => 1, 'pid' => 0, 'name' => '江西省'),
2 => array('id' => 2, 'pid' => 0, 'name' => '黑龙江省'),
3 => array('id' => 3, 'pid' => 1, 'name' => '南昌市'),
4 => array('id' => 4, 'pid' => 2, 'name' => '哈尔滨市'),
5 => array('id' => 5, 'pid' => 2, 'name' => '鸡西市'),
6 => array('id' => 6, 'pid' => 4, 'name' => '香坊区'),
7 => array('id' => 7, 'pid' => 4, 'name' => '南岗区'),
8 => array('id' => 8, 'pid' => 6, 'name' => '和兴路'),
9 => array('id' => 9, 'pid' => 7, 'name' => '西大直街'),
10 => array('id' => 10, 'pid' => 8, 'name' => '东北林业大学'),
11 => array('id' => 11, 'pid' => 9, 'name' => '哈尔滨工业大学'),
12 => array('id' => 12, 'pid' => 8, 'name' => '哈尔滨师范大学'),
13 => array('id' => 13, 'pid' => 1, 'name' => '赣州市'),
14 => array('id' => 14, 'pid' => 13, 'name' => '赣县'),
15 => array('id' => 15, 'pid' => 13, 'name' => '于都县'),
16 => array('id' => 16, 'pid' => 14, 'name' => '茅店镇'),
17 => array('id' => 17, 'pid' => 14, 'name' => '大田乡'),
18 => array('id' => 18, 'pid' => 16, 'name' => '义源村'),
19 => array('id' => 19, 'pid' => 16, 'name' => '上坝村'),
);
header("Content-Type: text/html; charset=utf-8");
echo "<pre>";
print_r(genTree5($items));
print_r(genTree9($items));
echo "</pre>";
|
打印结果太长,请自行测试:
原本写到这里就基本差不多了,但是最近有人一直在问这个代码有BUG,于是做几个解答:
从上面代码看出,要分类得数据是要按照严格规范来进行,如下:
我之前有发表过一篇文章专门讲解无限分类的原理,大家如果觉得困惑的话,请移步到这里:
这应该是质疑声最多的话了,这样的话明显带有几个错误:
那么怎样才能使自己的数据按照规范提供:
sql按照关键ID查询,例如:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
$data = array();
$result = mysqli::query('SELECT `id`, `pid`, `name` FROM `table`;');
if ($result->num_rows)
{
while (FALSE != ($row = $this->fetch_assoc()))
{
$id = $row['id'];
$data[$id] = $row;
}
}
$data = genTree5($data);
|
非sql查询呢,那么你可以自己创建一个索引出来,如下:
|
1
2
3
4
5
6
7
8
|
$data = array();
foreach($result as $value)
{
$id = $value['id'];
$data[$id] = $value;
}
$data = genTree5($data);
|
比如上面的排序都使按照id来的,这违背了我的排序的意图。看到有朋友这样留言,其实这也是对分类方法进行了误解,我想说明的是:
这个方法只提供了分类,他单纯的为分类而产生,而不是排序,排序是排序,分类是分类,请分开理解。
ok,那如何来排序呢?比如我希望黑龙江在江西上面,赣州又在南昌上面,诸如此类等。刚才也提到了,分类和排序是两个概念,既然这里多了一个分类的“元素”,再来看上面的数据规范,那么应当加上一个新的规范条件:
回到上面城市示例:我希望黑龙江在江西上面,赣州又在南昌上面,怎么做?
SQL查询版:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
$data = array();
$result = mysqli::query('SELECT `id`, `pid`, `name` FROM `table` ORDER BY `num` ASC;');
if ($result->num_rows)
{
while (FALSE != ($row = $this->fetch_assoc()))
{
$id = $row['id'];
$data[$id] = $row;
}
}
$data = genTree5($data);
|
非SQL查询,可以通过php二维排序:
array_multisort的方法以前有提过了,这里提供uasort的示例:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class ArrSort
{
private $_name;
public function __construct($name)
{
$this->_name = $name;
}
public function num($x, $y)
{
return (Int)$x[$this->_name] > (Int)$y[$this->_name];
}
private function str($x, $y)
{
return strcasecmp($x[$this->_name], $y[$this->_name]);
}
};
// 根据数字进行排序
uasort($data, array(new ArrSort('num'), 'num'));
// 根据字符进行排序
uasort($data, array(new ArrSort('char'), 'str'));
|
我们增加点难度,比如上海,我们想要搞特殊,把他单独提升到第一位,怎么做呢?
代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
|
$data = array();
foreach($result as $key => $val)
{
if ($val['name'] == '上海')
{
$data[$key] = $val;
unset($result[$key]);
}
}
$data = array_merge($data, $result);
|
如果大家有兴趣,自己可以试着想想把上海放在中间特定某一个位置怎么做,把上海放在末位又该怎么做。
以上只是列举了一小部分,方法有很多,大家自己去发掘。上面这个分类的方法还是非常好用的,他让我们告别了繁琐的递归,提高了我们代码执行效率,方法已提供了,不能因为不会用就说这个方法是有bug。这就好比提供给你碗和筷子了,但是饭还是要自己盛来吃的嘛。