之前面试的时候碰到过这个问题,没有能回答出来。今天搜集了一些资料,总结了一下就记了下来,应该以后还要上。顺便也和大家讨论下。
- <?php
- $arr = array(
- array('id'=>1, 'pid'=>0, 'order'=>0),
- array('id'=>2, 'pid'=>0, 'order'=>1),
- array('id'=>3, 'pid'=>2, 'order'=>0),
- array('id'=>4, 'pid'=>0, 'order'=>2),
- array('id'=>5, 'pid'=>3, 'order'=>0),
- array('id'=>6, 'pid'=>1, 'order'=>0),
- array('id'=>7, 'pid'=>1, 'order'=>1)
- );
- function order($a,$b) {
- if($a['pid'] == $b['pid']) {
- if($a['order'] > $b['order'])
- return 1;
- elseif($a['order'] < $b['order'])
- return -1;
- return 0;
- }
- return $a['pid'] > $b['pid'] ? 1 : -1;
- }
- usort($arr, "order");
- $new_arr = array();
- $temp_arr = array();
- foreach($arr as $row) {
- $row['child'] = array();
- if($row['pid'] == 0) {
- $i = count($new_arr);
- $new_arr[$i] = $row;
- $temp_arr[$row['id']] = &$new_arr[$i];
- }
- else {
- $i = count($temp_arr[$row['pid']]['child']);
- $temp_arr[$row['pid']]['child'][$i] = $row;
- $temp_arr[$row['id']] = &$temp_arr[$row['pid']]['child'][$i];
- }
- }
- echo "<pre>", print_r($new_arr, true), "</pre>";
- ?>
$arr就是要分级的数据,id是自身唯一的id。pid是指父节点的id,其中0是最高分级。order就是排列顺序,分级相同时按order排序。order函数是为 usort 排序提供的排序函数,如果对 usort 不太理解,可以参考下 http://www.phpfans.net/bbs/PHPfunction.php?function=usort order函数对同级别的根据order值排序,不同级别的父节点在子节点前面。避免先出现子节点再出现父节点。
$new_arr是用了保存分级后的数据,$temp_arr用来保存临时的数据。
好了,下面来看一下这个排列的过程。$row['child'] 是用来保存比当前分级更低级别的数据,如果$row['child']为空,则当前没有更低分级。当 $row['pid'] == 0 时,即使最高级别,直接保存到 $new_arr 数组。其中下面这步是非常关键的:$temp_arr[$row['id']] = &$new_arr[$i]; 这个和一般的赋值 $temp_arr[$row['id']] = $new_arr[$i]; 不同,注意 &。这个是传引用。php中的传引用和c中的传址是一样的效果。如果大家不好理解,下面我举个例子大家就易于明白了。
- <?php
- $arr = array(1, 2, 3);
- $new_arr = &$arr;
- $new_arr[] = 4;
- print_r($new_arr);
- print_r($arr);
- ?>
可以看到现在 $new_arr 和 $arr 都是 array(1, 2, 3, 4)。也就是说接下来我们改变 $temp_arr[$row['id']] 的值,$new_arr[$i]也会跟着改变。
order函数排序后pid为0的排在最前面,foreach循环会现将pid为0的级别保存到$new_arr:$new_arr[$i] = $row;并通过传引用赋值给$temp_arr:$temp_arr[$row['id']] = &$new_arr[$i]; $temp_arr的索引是$row自身的id。
当 $row['pid'] != 0 时,也就是该分级有父节点,该父节点的id就应该等于该分级的pid。我们要做的是将该分级$row保存到父节点的 child 数组里。而我们现在可以通过改变 $temp_arr[$row['pid']] 的值达到这样效果:$temp_arr[$row['pid']]['child'][$i] = $row;同样将该分级的值引用赋值给$temp_arr:$temp_arr[$row['id']] = &$temp_arr[$row['pid']]['child'][$i];以便该级别的子节点对该级别的child进行赋值。循环过后就已经讲数据分级好了。