<?php
/**
 * PHP数组无限级分组
 * @baseFrom http://blog.phpdr.net/php%E6%97%A0%E6%9E%81%E5%88%86%E7%BB%84.html
 *
 * @param array $list       数据源
 * @param mixed $columns    最内层需要提取数据的字段
 * @param mixed $group      分组  如果为空,不分组;     如果为数组,多个值按顺序分别作为多维数组键值
 * @param mixed $primary    主键  如果为空,以数字为键值;如果为数组,以多个值拼接作为键值
 * @return array
 */
function dict(array $list$columns null$group null$primary null) {
    if (! isset ( 
$primary )) {
        
$primary = array ();
    }
    if (
is_string $primary )) {
        
$primary = array (
                
$primary
        
);
    }
    if (
is_string $group )) {
        
$group = array (
                
$group
        
);
    }
    
$listNew = array ();
    foreach ( 
$list as $v ) {
        
//如果指定主键,拼接主键
        
$key null;
        foreach ( 
$primary as $p ) {
            
$key .= $v [$p];
        }
        
//提取字段
        
if (isset ( $columns )) {
            
//$columns = array(null) 提取字段结果为null
            
if (is_array $columns ) && === count $columns ) && $columns [0] === null) {
                
$vNew null;
            } else {
                
$vNew = array ();
                if (
is_array $columns )) {
                    
//$columns = array('col1', 'col2') 循环提取字段,若数组为空,则提取字段结果为空数组
                    
foreach ( $columns as $k1 => $v1 ) {
                        if (
is_int $k1 )) {
                            
$k1 $v1;
                        }
                        
$vNew [$k1] = $v [$v1];
                    }
                } else {
                    
$vNew $v [$columns];
                }
            }
        } else {    
//$columns = null 提取所有字段
            
$vNew $v;
        }
        
//切换数据存储位置到指定分组
        
if (isset ( $group )) {
            
$vGroup = &$listNew;
            
//遍历分组
            /*
            foreach ( $group as $v2 ) {
                //分组不存在,设置为空数组
                if (!isset ( $vGroup[$v [$v2]] )) {
                    $vGroup [$v [$v2]] = array ();
                }
                //当前分组切换到新位置
                $vGroup = &$vGroup [$v [$v2]];
            }
            //*/
            
foreach ( $group as $v2 ) {
                if (isset ( 
$vGroup ) && array_key_exists $v [$v2], $vGroup )) {
                    
$vGroup = &$vGroup [$v [$v2]];
                } else {
                    
$vGroup [$v [$v2]] = array ();
                    
$vGroup = &$vGroup [$v [$v2]];
                }
            }
            
//指定主键,用主键为键值存储字段信息
            
if (isset ( $key )) {
                
$vGroup [$key] = $vNew;
            } else {    
//未指定主键,以索引数组存储字段信息
                
$vGroup [] = $vNew;
            }
            unset(
$vGroup);
        } else {
            
//指定主键,用主键为键值存储字段信息
            
if (isset ( $key )) {
                
$listNew [$key] = $vNew;
            } else {    
//未指定主键,以索引数组存储字段信息
                
$listNew [] = $vNew;
            }
        }
    }
    return 
$listNew;
}
//示例
$list = array ();
$list [] = array (
        
'id' => 1,
        
'name' => '学生1',
        
'school' => '学校1',
        
'class' => '班级1'
);
$list [] = array (
        
'id' => 4,
        
'name' => '学生4',
        
'school' => '学校2',
        
'class' => '班级2'
);
$list [] = array (
        
'id' => 2,
        
'name' => '学生2',
        
'school' => '学校1',
        
'class' => '班级2'
);
$list [] = array (
        
'id' => 3,
        
'name' => '学生3',
        
'school' => '学校2',
        
'class' => '班级1'
);
$list [] = array (
        
'id' => 5,
        
'name' => '学生5',
        
'school' => '学校2',
        
'class' => '班级3'
);

echo 
"<br><pre>\n";

//源数组
echo "<br>0. 源数组<br>\n";
print_r($list);

//1. 提取name字段
echo "<br>1. 提取name字段<br>\n";
print_r dict $list'name' ) );

//2. 提取空字段(数据项为null)
echo "<br>2. 提取空字段(数据项为null)<br>\n";
var_dump dict $list, array (
        
null
) ) );

//3. 提取空字段(数据项为array)
echo "<br>3. 提取空字段(数据项为array)<br>\n";
var_dump dict $list, array () ) );

//4. 提取多个指定字段,以id为主键
echo "<br>4. 提取多个指定字段,以id为主键<br>\n";
print_r dict $list, array (
        
'id',
        
'name',
        
'school'
), null'id' ) );

//5. 指定两个字段拼接为主键,提取所有字段
echo "<br>5. 指定两个字段拼接为主键,提取所有字段<br>\n";
print_r dict $listnullnull, array (
        
'class',
        
'name'
) ) );

//6. 以school为分组,以id为主键,提取name字段
echo "<br>6. 以school为分组,以id为主键,提取name字段<br>\n";
print_r dict $list, array (
        
'name'
), 'school''id' ) );

//7. 以school和class为分组,以id为主键,提取name字段
echo "<br>7. 以school和class为分组,以id为主键,提取name字段<br>\n";
print_r dict $list, array (
        
'name'
), array (
        
'school',
        
'class'
), 'id' ) );

//8. 无限级重组演示(数据源比较单薄,暂且这么演示)
echo "<br>8. 无限级重组演示(数据源比较单薄,暂且这么演示)<br>\n";
print_r dict $list, array (
        
'name'
), array (
        
'school',
        
'class',
        
'school',
        
'class',
        
'school',
        
'class',
), 
'id' ) );