💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 常用数组函数大全 [toc] ## 1. 数组基础 ### 1.1 概述与分类 - 数组是典型的复合类型数据,它的值是由零个或多个**键值对**构成 - 数组中的每一个"键值对", 称之为**数组成员** 或者 **数组元素** - 根据**键**的类名,可以将数组分为二类: | 序号 | 分类 | 描述 | | ---- | -------- | ------------------------------- | | 1 | 索引数组 | 键名默认是从 0 开始递增的正整数 | | 2 | 关联数组 | 键名是由语义化的字符串组成 | > 索引数组键名可使用数字字符串,所以,索引数组也可视为关联数组的一个子集 ```php // 1. 数组分类 // 1.1 索引数组 $goods = [0=>'A1060', 1=>'华为笔记本电脑', 2=>'MateBook X Pro', 3=>9999]; printf('<pre>%s</pre>', print_r($goods,true)); // 如果键名是从0开始递增的正整数,可以省略键名 $goods = ['A1060', '华为笔记本电脑', 'MateBook X Pro', 9999]; printf('<pre>%s</pre>', print_r($goods,true)); // 键名可以不连续,可以是负数,甚至可以是小数 $goods = ['A1060', 5=>'华为笔记本电脑', 3.14=>'MateBook X Pro', -88=>9999]; printf('<pre>%s</pre>', print_r($goods,true)); // 打印键名时,只会显示键名的整数部分, 即小数键名会自动取整,访问时用原始键名或取整键名都可以 echo "{$goods[3.14]} --- {$goods[3]}<br>"; // 访问全部数组成员 // 1.2 关联数组 // 键名为非数字的字符串,例如将上面的索引数组,用以下方式定义,显然比纯数字的索引要直观得多 $goods = ['id'=>'A1060', 'name'=>'华为笔记本电脑', 'model'=>'MateBook X Pro', 'price'=>9999]; printf('<pre>%s</pre>', print_r($goods,true)); // 为什么特别强调是非数字字符串呢?因为索引数组的数字键名也可以这样表示 $goods = ['0'=>'A1060', '1'=>'华为笔记本电脑', '2'=>'MateBook X Pro', '3'=>9999]; printf('<pre>%s</pre>', print_r($goods,true)); // 访问的时候,可以使用数字键名,也可以使用字符串数字键名 echo "{$goods[1]} --- {$goods['1']}<br>"; // 所以, 索引数组,也可以理解为键名是数字字符串的关联数组 // 从这个角度看, 索引数组,可以视为"关联数组"的一个子集 // 因此, 数字键名与字符串键名在同一个数组中出现,其实也是合法的 $goods = [3=>'A1060', 'name'=>'华为笔记本电脑', 10=>'MateBook X Pro', 'price'=>9999]; printf('<pre>%s</pre>', print_r($goods,true)); // 如果省略数字键名部分, 默认使用从0开始递增的正整数为元素编号 $goods = ['A1060', 'name'=>'华为笔记本电脑', 'MateBook X Pro', 'price'=>9999]; printf('<pre>%s</pre>', print_r($goods,true)); ``` ### 1.2 定义与访问 | 序号 | 定义 | 描述 | | ---- | ------------- | ------------------------------ | | 1 | `array()`函数 | 传统定义方式,已淘汰或不再推荐 | | 2 | `[...]`结构 | php5.4+支持, 语法简洁,推荐使用 | > 访问遵循按键名访问的规则, 多维数组与不例外 ```php # 2. 数组的定义与访问 // array()函数定义数组 $staff1 = array('1010', '八戒','bj@php.cn'); $staff2 = array('id'=>'1010', 'name'=>'八戒', 'email'=>'bj@php.cn'); printf('<pre>%s%s</pre>', print_r($staff1,true),print_r($staff2,true)); // 方括号[]简化定义: php 5.4+,与JavaScript类似, 推荐使用 $staff3 = ['1010', '八戒', 'bj@php.cn']; $staff4 =['id'=>'1010', 'name'=>'八戒', 'email'=>'bj@php.cn']; printf('<pre>%s%s</pre>', print_r($staff3,true),print_r($staff4,true)); // 使用方括号,还可以逐个定义数组成员 $staff5['id'] = '1020'; $staff5['name'] = '悟空'; $staff5['email'] = 'wk@php.cn'; printf('<pre>%s</pre>', print_r($staff5,true)); // 如果是逐个定义索引数组成员,如果省略键名,则键名默认从0开始递增 $staff6[] = '1030'; $staff6[] = '唐僧'; $staff6[] = 'ts@php.cn'; printf('<pre>%s</pre>', print_r($staff6,true)); // 数组成员是按键名访问的 // 访问索引数组成员 echo "$staff6[1] 的邮箱是: $staff6[2]<br>"; // 访问关联数组成员 // 双引号中的数组成员变量,键名部分使用了单引号, 所以一定要给数组变量加上大括号定界符 echo "{$staff5['name']} 的邮箱是: {$staff5['email']}<br>"; // 数组成员的类型不受限制,可以是字面量,可以是变量,可以是对象等 $age = 30; $staff7 =['id'=>'1010', 'name'=>'八戒', 'age'=>$age, 'email'=>'bj@php.cn']; printf('<pre>%s</pre>', print_r($staff7,true)); // 如果数组成员的类型仍是一个数组,则构成多维数组 // 多维数组中最常用的是二维数组,二维数组在php操作数据库中非常重要 $users = [ 0=>['id'=>'101', 'name'=>'玉帝', 'age'=>88], 1=>['id'=>'102', 'name'=>'王母', 'age'=>78], 2=>['id'=>'101', 'name'=>'如来', 'age'=>68], ]; printf('<pre>%s</pre>', print_r($users,true)); // 访问二维数组成员,与访问一维数组成员类似 // 先定位到某一个成员,再访问它的全部数据, 下例返回的是"如来"的数据 printf('<pre>%s</pre>', print_r($users[2],true)); // 查看如来的年龄 echo $users[2]['age']; ``` ### 1.3 遍历 | 序号 | 方式 | 描述 | | ---- | -------- | ----------------- | | 1 | 逐个遍历 | 使用数组内部指针 | | 2 | 循环遍历 | 使用`foreach`结构 | 数组内部指针函数: | 序号 | 函数 | 描述 | | ---- | --------- | -------------------------------- | | 1 | `current` | 获取当前元素的值 | | 2 | `key` | 获取当前元素的键名 | | 3 | `next` | 将数组中的内部指针向前移动一位 | | 4 | `prev` | 将数组的内部指针倒回一位 | | 5 | `end` | 将数组的内部指针指向最后一个单元 | | 6 | `reset` | 将数组的内部指针指向第一个单元 | `foreach`遍历: | 序号 | 语法 | 描述 | | ---- | -------------------------------- | ------------ | | 1 | `foreach ($arr as $value)` | 遍历"值" | | 2 | `foreach ($arr as $key=>$value)` | 遍历"键与值" | | 3 | `foreach ($arr as list(...))` | 解构遍历 | > foreach 不支持 @ 抑制错误 ```php # 3. 数组遍历 // 数据遍历通常与数组元素的处理结合在一起的,与简单的打印输出不一样 // 数组元素的处理, 最常用的就是数据的格式化 // 3.1 逐个遍历: 数组内部指针 // 如果没有对数组进行过遍历操作,则数组内部指针默认停留头部,即指向第一个元素 $stu = ['id' => '1020', 'name' => '金莲', 'age' => 18, 'course' => 'php', 'grade' => 68]; // 获取当前数据成员的键名与值 // current(): 当前成员值, key(): 当前成员的键名 printf('[%s] => %s<br>', key($stu), current($stu)); // next():移动指针,指向下一个数组成员 next($stu); printf('[%s] => %s<br>', key($stu), current($stu)); // 再次移动 next($stu); printf('[%s] => %s<br>', key($stu), current($stu)); // 如果要访问最后一个成员,是否一直next()下去吗?当然不用,可以直接定位到数组末尾 end($stu); printf('[%s] => %s<br>', key($stu), current($stu)); // prev(): 向前移动指针,指向当前成员的前一个前面 prev($stu); printf('[%s] => %s<br>', key($stu), current($stu)); // 同样,如果要从当前位置直接跳转到第一个成员,也不用逐级返回,可以重置数组指针即可 // 数组指针重置后, 会自动指向第一个成员 reset($stu); printf('[%s] => %s<br>', key($stu), current($stu)); echo '<hr>'; // 3.2 自动遍历: 循环实现 // 你可能会很自然的想到,使用while,配合数组内部指针来遍历,咱们试试看 reset($stu); while (true) { printf('[%s] => %s<br>', key($stu), current($stu)); if (next($stu)) { continue; } else { break; } } echo '<hr>'; // 看上去似乎正常,其实并非如此,这是假定数组所有元素都是true的前提下 // 如果有数组成员值为false,或者可转为false的值,如null,就会提前结束遍历 $stu = ['id' => '1020', 'name' => '金莲', 'age' => null, 'course' => 'php', 'grade' => 68]; reset($stu); while (true) { printf('[%s] => %s<br>', key($stu), current($stu)); if (next($stu)) { continue; } else { break; } } // age后面的二个成员将不会打印输出 echo '<hr>'; // 既然while循环不能遍历, 那么for循环是否可以呢? // 看到for循环,首先会想到遍因索引数组,这是必然的 $arr = [100, 'a', 89, true, [1, 2, 3]]; for ($i = 0; $i < count($stu); $i++) { // 数组成员也可能仍然是数组,所以使用了is_array()判断一下,针对不同类型使用不同方式输出 echo is_array($arr[$i]) ? print_r($arr[$i], true) : $arr[$i], '<br>'; } echo '<hr>'; // 看上去,for循环工作得很好,那么for循环能否正确遍历关联数组呢? reset($stu); for ($i = 0; $i < count($stu); $i++) { printf('[%s] => %s<br>', key($stu), current($stu)); next($stu); } // 可以看出, for循环可以正常输出关联数组,并且能正确识别出null/false元素 // 这是因为它是根据数组成员数量做为循环条件的, 并非根据当前数组指针是否指向空元素来判断 // 尽管for循环可以遍历数组, 但仍然不方便,特别是遍历关联数组时,循环变量只是摆设,并且必须手工移到数组指针 // 针对数组类型,PHP预定义了foreach语法结构,专用于遍历数组类型的数据 echo '<hr>'; foreach ($stu as $key => $value) { printf('[%s] => %s<br>', $key, $value); } // 对于索引数组,我们通常只关注值,可以省略循环变量的键名$key echo '<hr>'; foreach ($arr as $value) { echo is_array($value) ? print_r($value, true) : $value, '<br>'; } echo '<hr>'; // foreach()在遍历二维数组时特别方便,以下用二维数组模拟数据表查询结构 $users = [ 0 => ['id' => '101', 'name' => '玉帝', 'age' => 88], 1 => ['id' => '102', 'name' => '王母', 'age' => 78], 2 => ['id' => '101', 'name' => '如来', 'age' => 68], ]; // 索引是默认值,可以省略 $users = [ ['id' => '101', 'name' => '玉帝', 'age' => 88], ['id' => '102', 'name' => '王母', 'age' => 78], ['id' => '101', 'name' => '如来', 'age' => 68], ]; // 也可将多维数组写在一行定义 // 前面可能定义过$users数组,为防止后面数据被追加,所以先清空 // 第一行必须加上$users = []; 清空该数组 $users = []; $users[] = ['id' => '101', 'name' => '玉帝', 'age' => 88]; $users[] = ['id' => '102', 'name' => '王母', 'age' => 78]; $users[] = ['id' => '101', 'name' => '如来', 'age' => 68]; print_r($users); foreach ($users as $user) { foreach ($user as $key => $value) { echo "$key => $value <br>"; } echo '<hr>'; } // 更多场景下, 我们并不会使用双重循环来输出二维数组 foreach ($users as $user) { printf('id=%s, name=%s, age=%s<br>', $user['id'], $user['name'], $user['age']); } echo '<hr>'; // 如果二维数组中字段并不多,可以使用list()进行数组解包,类似于ES6中的解构赋值 // 提示: 在foreach中使用list()解构数组, 要求 PHP5.5+ foreach ($users as list('id' => $id, 'name' => $name, 'age' => $age)) { printf('id=%s, name=%s, age=%s<br>', $id, $name, $age); } echo '<hr>'; // 对于索引数组, list()解构更加方便 $staffs = null; $staffs[] = ['2020', '八戒', 29]; $staffs[] = ['2021', '悟空', 39]; $staffs[] = ['2022', '唐僧', 49]; foreach ($staffs as list($id, $name, $age)) { printf('id=%s, name=%s, age=%s<br>', $id, $name, $age); } echo '<hr>'; // list()中的参数数量可以少于数组元素数量,但不能多于 foreach ($staffs as list($id, $name)) { printf('id=%s, name=%s<br>', $id, $name); } // list()参数过多,会报Notice消息级警告错误 foreach ($staffs as list($id, $name, $age, $email)) { printf('id=%s, name=%s, email=%s<br>', $id, $name,$age, $email); } echo '<hr>'; // list()中允许嵌套list, 用于解析多维数组 // $staffs中添加一个字段, 表示js和php的成绩 $staffs = null; $staffs[] = ['2020', '八戒', 29, [67, 88]]; $staffs[] = ['2021', '悟空', 39, [99, 31]]; $staffs[] = ['2022', '唐僧', 49, [56, 63]]; foreach ($staffs as list($id, $name, $age, list($js, $php))) { printf('id=%s, name=%s, age=%s, js=%s, php=%s<br>', $id, $name,$age, $js, $php); } echo '<hr>'; // foreach()不仅仅可以遍历数组,还可以遍历对象属性 $obj = new stdClass(); $obj->name = 'admin'; $obj->email = 'admin@php.cn'; $obj->role = 'custom'; foreach ($obj as $prop=>$value) { printf('%s => %s<br>',$prop, $value); } ``` --- ## 2. 数组函数 ### 2.1. 键名相关 | 序号 | 函数 | 描述 | | ---- | ------------------ | -------------------------- | | 1 | `array_keys` | 获取所有键名组成的数组 | | 2 | `array_key_exists` | 是否存在指定键名 | | 3 | `array_key_last` | 获取最后一个键名 `php7.3+` | | 4 | `array_key_first` | 获取第一个键名 `php7.3+` | ```php // ## 键名相关函数 // array_keys: 获取所有键名组成的数组 $arr = ['id' => 1, 'username' => 'admin', 'email' => 'admin@php.cn']; print_r(array_keys($arr)); echo '<hr>'; // array_key_exists: 是否存在指定键名 echo (array_key_exists('email', $arr) ? '存在' : '不存在') . '<hr>'; // array_key_last: 获取最后一个键名php7.3+ echo array_key_last($arr) . '<hr>'; // array_key_first: 获取第一个键名php7.3+ echo array_key_first($arr) . '<hr>'; ``` --- ### 2.2 与值相关 | 序号 | 函数 | 描述 | | ---- | -------------- | -------------------------- | | 1 | `array_values` | 返回数组中所有值组成的数组 | | 2 | `in_array` | 检查数组中是否存在某个值 | | 3 | `array_search` | 搜索指定的值,返回键名 | | 4 | `array_unique` | 删除重复的值 | ```php // ## 与值相关的数组函数 // array_values: 返回数组中所有值组成的数组 $arr = [3 => 10, 9 => 20, 0 => 'html', 'id' => 'css', 20 => 20, 30]; print_r($arr); echo '<hr>'; print_r(array_values($arr)); echo '<hr>'; // 键名被打乱的数组进行重置 // in_array: 检查数组中是否存在某个值 echo (in_array('html', $arr) ? '存在' : '不存在') . '<br>'; // array_search: 搜索指定的值,返回键名 echo array_search('css', $arr); echo '<br>'; echo $arr[array_search('css', $arr)] . '<br>'; // array_unique: 删除重复的值 $newArr = array_unique($arr); print_r($newArr); ``` --- ### 2.3 与统计相关 | 序号 | 函数 | 描述 | | ---- | -------------------- | -------------------------- | | 1 | `count` | 统计元素数量或对象属性数量 | | 2 | `array_count_values` | 统计所有值的出现频率 | ```php // 与统计相关 $arr = [10, 3, 5, 3, 10, 5, 7, 3, 10, 7, 7]; printf('<pre>%s</pre>', print_r($arr, true)); // count: 统计元素数量或对象属性数量 echo '数组元素数量: ' . count($arr); // array_count_values: 统计所有值的出现频率 $res = array_count_values($arr); printf('<pre>%s</pre>', print_r($res, true)); ``` --- ### 2.4 与计算相关 | 序号 | 函数 | 描述 | | ---- | --------------- | ---------------------- | | 1 | `array_sum` | 对数组中所有值求和 | | 2 | `array_product` | 计算数组中所有值的乘积 | ```php // 与计算相关 $arr = [10, 20, 30]; // array_sum: 对数组中所有值求和 echo array_sum($arr) . '<hr>'; // array_product: 计算数组中所有值的乘积 echo array_product($arr); ``` --- ### 2.5 栈与队列 | 序号 | 函数 | 描述 | | ---- | --------------- | ------------------------ | | 1 | `array_push` | 从尾部添加一个或多个元素 | | 2 | `array_pop` | 从尾部删除最后一个元素 | | 3 | `array_unshift` | 从头部添加一个或多个元素 | | 4 | `array_shift` | 从头部删除一个元素 | ```php // 栈与队列 // 栈: 后进先出(LIFO): 最后进入的元素最先出来 // 队列: 先进先出(FIFO): 最先插入的数据最先出来 // 1. 栈操作: 尾部进行 $stack = []; // 1.1. array_push: 进栈, 返回数量 echo array_push($stack, 10) . '<br>'; echo array_push($stack, 20, 30) . '<br>'; print_r($stack); echo '<hr>'; // 1.2. array_pop: 出栈, 返回元素 echo array_pop($stack) . '<br>'; echo array_pop($stack) . '<br>'; echo array_pop($stack) . '<br>'; var_dump(array_pop($stack)); echo '<hr>'; // 2. array_unshift: 栈操作: 头部进行, 返回数量 $stack = []; // 2.1 入栈 echo array_unshift($stack, 'one') . '<br>'; echo array_unshift($stack, 'two', 'three') . '<br>'; print_r($stack); echo '<hr>'; // 2.2 array_shift: 出栈, 返回元素 echo array_shift($stack) . '<br>'; echo array_shift($stack) . '<br>'; echo array_shift($stack) . '<br>'; var_dump(array_pop($stack)); echo '<hr>'; // 3. 队列: // 尾部添加, 头部出队 array_push()+array_shift() // 进队 $queue = []; echo array_push($queue, 10, 20, 30) . '<br>'; print_r($queue); echo '<hr>'; //出队 echo array_shift($queue) . '<br>'; echo array_shift($queue) . '<br>'; echo array_shift($queue) . '<br>'; // 头部添加入队, 尾部出队 array_unshift() + array_pop() $queue = []; echo array_unshift($queue, 'one', 'two', 'three'); print_r($queue); echo '<hr>'; echo array_pop($queue) . '<br>'; echo array_pop($queue) . '<br>'; echo array_pop($queue) . '<br>'; var_dump(array_pop($queue)); echo '<hr>'; ``` --- ### 2.6 排序 #### 2.6.1 对值排序 | 序号 | 函数 | 描述 | | ---- | -------- | -------------------------- | | 1 | `sort` | 按值升序排序, 索引重排 | | 2 | `asort` | 按值升序排序, 索引保持不变 | | 3 | `rsort` | 按值降序排序, 索引重排 | | 4 | `arsort` | 按值降序排序, 索引保持不变 | #### 2.6.2 对键排序 | 序号 | 函数 | 描述 | | ---- | -------- | -------------- | | 1 | `ksort` | 按键名升序排序 | | 2 | `krsort` | 按键名降序排序 | #### 2.6.3 自定义排序 | 序号 | 函数 | 描述 | | ---- | -------- | -------------------------------- | | 1 | `usort` | 自定义函数对值进行排序 | | 2 | `uasort` | 自定义函数对值排序并保持索引不变 | | 3 | `uksort` | 自定义函数对键名进行排序 | #### 2.6.4 自然排序 | 序号 | 函数 | 描述 | | ---- | ------------- | -------------------- | | 1 | `natsort` | 支持数字型字符串排序 | | 2 | `natcasesort` | 不区分大小写 | #### 2.6.5 乱序反转 | 序号 | 函数 | 描述 | | ---- | --------------- | ---------------------- | | 1 | `shuffle` | 随机打乱一个数组的顺序 | | 2 | `array_flip` | 交换数组中的键和值 | | 3 | `array_reverse` | 反转一个数组 | 示例: ```php // 排序: 参数是引用传值, 直接更新原始数组 // 1. 对值排序 $arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46]; printf('原始数组:<pre>%s</pre><hr>', print_r($arr, true)); // 1.1升序 // 升序: 索引重置 sort($arr); printf('升序索引重置:<pre>%s</pre>', print_r($arr, true)); // 升序: 索引保持不变 // 数组还原, 便于观察排序结果 $arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46]; asort($arr); printf('升序索引不变:<pre>%s</pre>', print_r($arr, true)); // 1.2 降序 // 降序: 索引重置 $arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46]; rsort($arr); printf('降序索引重置:<pre>%s</pre>', print_r($arr, true)); // 降序: 索引保持不变 $arr = [30, 4, 82, 15, 20, 'abc', 'hello', 2, 46]; arsort($arr); printf('降序索引不变:<pre>%s</pre>', print_r($arr, true)); echo '<hr>'; // 2. 对键排序 $arr = ['e' => 10, 'a' => 30, 'p' => 50]; // 2.1 按键名升序 ksort($arr); printf('按键名升序:<pre>%s</pre>', print_r($arr, true)); // 2.2 按键名降序 $arr = ['e' => 10, 'a' => 30, 'p' => 50]; krsort($arr); // 降序 printf('按键名降序:<pre>%s</pre>', print_r($arr, true)); echo '<hr>'; // 3. 自定义排序 $arr = [90, 33, 4, 10, 2, 12]; // 3.1 自定义升序 usort($arr, function ($a, $b) { return $a - $b; }); printf('自定义升序:<pre>%s</pre>', print_r($arr, true)); // 3.2 自定义降序 $arr = [90, 33, 4, 10, 2, 12]; uasort($arr, function ($a, $b) { return $a - $b; }); printf('自定义升序且索引不变:<pre>%s</pre>', print_r($arr, true)); echo '<hr>'; // 4. 自然排序 $arr = ['img1.jpg', 'img5.jpg', 'img10.jpg', 'img8.jpg']; sort($arr); // 不能正确识别出字母数字字符串 "1" 和 "10" 之间的区别 printf('普通升序:<pre>%s</pre>', print_r($arr, true)); $arr = ['img1.jpg', 'img5.jpg', 'img10.jpg', 'img8.jpg']; // 自然排序可以正确识别出字母数字字符串中的数值 natsort($arr); printf('自然升序:<pre>%s</pre>', print_r($arr, true)); echo '<hr>'; // 5. 乱序反转 $arr = ['id' => 109, 'username' => 'peter', 'age' => 27, 'salary' => 99999]; // 随机打乱一个数组,引用传参, 会改变原数组 shuffle($arr); printf('随机扰乱:<pre>%s</pre>', print_r($arr, true)); // 翻转一个数组,返回一个新数组,翻转是指第一个变成最后一个,依次类推 $arr = array_reverse($arr); printf('翻转数组:<pre>%s</pre>', print_r($arr, true)); $arr = ['name' => 'admin', 'age' => 30, 'salary' => 8888]; // 注意键名的合法性,如果不是"integer"或"string"会有警告,且不会出现在结果中 $arr = ['name' => 'admin', 'age' => 30, 'salary' => false]; // 交换键值 $arr = array_flip($arr); printf('交换键值:<pre>%s</pre>', print_r($arr, true)); ``` --- ### 2.7 查询与替换 | 序号 | 函数 | 描述 | | ---- | ------------------------- | -------------------------------------- | | 1 | `array_slice` | 从数组中取出一部分 | | 2 | `array_splice` | 去掉数组中一部分并用其它值代替 | | 3 | `array_rand` | 从数组中随机取出一个或多个元素的键名 | | 4 | `array_column` | 获取多维数组中一列组成的新数组 | | 5 | `array_replace` | 使用后面数组的值替换第一个数组的值 | | 6 | `array_replace_recursive` | 使用传递的数组递归替换第一个数组的元素 | | 7 | `array_intersect` | 计算数组的交集 | | 8 | `array_intersect_assoc` | 返回数组交集,键名也做比较 | | 9 | `array_diff` | 返回数组的差集 | | 10 | `array_diff_assoc` | 返回数组差集,键名也做比较 | 示例: ```php ## 查询与替换 // 1. array_slice($arr,$offset,$length,$flag): 从数组中取出一部分 $stu = ['id' => 101, 'name' => '无忌', 'age' => 20, 'course' => 'php', 'grade' => 80]; // offset=0: 获取从索引0开始直到结束,即获取全部元素,这不是这个函数的主要使用场景 $res = array_slice($stu, 0); // 获取前2个 $res = array_slice($stu, 0, 2); // 从第2个开始获取3个 $res = array_slice($stu, 1, 3); // 第2个参数支持负数,数组索引反序从-1开始,-3表示从倒数第3个 // 从倒数第3个开始,获取2个 $res = array_slice($stu, -3, 2); // 第3个参数也支持负数,表示元素区间的结束索引(返回结果不包括结束索引对应的元素) // 注意结果中并不包括索引-1对应元素'grade' $res = array_slice($stu, 1, -1); // 第4个参数是布尔值,默认为false,针对索引数组才有意义 // 将$stu转为索引数组, false表示, 获取到的部分元素,索引重置,即从0开始重排 $res = array_slice(array_values($stu), 1, -1, false); // true: 表示保持元素在原始数组中的索引不变 $res = array_slice(array_values($stu), 1, -1, true); printf('<pre>%s</pre>', print_r($res, true)); echo '<hr>'; // 2. array_splice(&$arr...): 去掉数组中一部分并用其它值代替,引用传参,会更新原数组,键名自动重置 // 该函数功能非常强大,具有数组元素的: 删除, 替换, 增加功能 $arr = [10, 28, 9, 33, 56, 21, 82, 47]; printf('原始数组元素: <pre>%s</pre>', print_r($arr, true)); // 2.1 删除: 指定起始索引和元素数量即可,从第2个元素开始删除2个,返回被删除的元素 // $res = array_splice($arr, 1,2); // 2.2 替换: 传入第3个数组参数, 替换掉被删除的元素,如果数组元素数量与被删除元素数量相等,则可视为更新操作 // 为了便于观察结果,请将上一条array_splice()语句注释掉 // $res = array_splice($arr, 1,2, [888, 999]); // 如果只替换一个元素,则第四个参数不需要以数组形式出现,单值即可 // $res = array_splice($arr, 1,2, 888); // 2.3 增加: 如果第3个参数length的值为0,而又提供了第4个参数,表示不会有元素被删除,新元素会被插入到数组中 // $res = array_splice($arr, 1,0, [888, 999]); // 第2与第3个参数也支持负数,含义与array_slice()一样 // 将从倒数第3个元素开始的2个元素,替换成888,999 // $res = array_splice($arr, -3,2, [888, 999]); // 将从倒数第4个位置到倒数第2个位置之间的元素替换成888,999 (注意不包括-2位置的元素) $res = array_splice($arr, -4, -2, [888, 999]); printf('被删除的元素:<pre>%s</pre>', print_r($res, true)); printf('当前数组元素: <pre>%s</pre>', print_r($arr, true)); echo '<hr>'; // 3. array_rand: 从数组中随机取出一个或多个元素的键名,支持索引与关联数组 $arr = ['一等奖', '二等奖', '三等奖', '谢谢参与']; // 如果只传入一个参数,即数组,则只返回一个随机的键名 $res = array_rand($arr); printf('%s<br>', $res); // 当然这个键名对用户来说意义不大,用户真正感兴趣的是键名对应的值 printf('[%s] => %s<br>', $res, $arr[$res]); // 第二个参数是一个正整数,表示要取出的元素数量,返回一个键名组成的一维数组 // 例如,一次性随机取出三个,提高中奖率 $res = array_rand($arr, 3); printf('<pre>%s</pre>', print_r($res, true)); // 遍历键名数组,查看对应的中奖情况 foreach ($res as $key) { printf('%s<br>', $arr[$key]); } echo '<hr>'; // 4. array_column: 获取多维数组中一列组成的新数组 $arr = null; $arr[] = ['id' => 101, 'name' => 'jack', 'age' => 20]; $arr[] = ['id' => 102, 'name' => 'mike', 'age' => 30]; $arr[] = ['id' => 103, 'name' => 'pony', 'age' => 40]; // 只指定返回数组的列名称, 默认返回列值组成的一维索引数组,键名为默认值 $res = array_column($arr, 'name'); // 为了更加精准描述结果,允许自定义返回数组的键名,键名须是原数组中除第2个参数之外键名 $res = array_column($arr, 'name', 'id'); printf('<pre>%s</pre>', print_r($res,true)); // 这个参数是数据表查询, 获取单个字符的值时非常有用 echo '<hr>'; // 5. array_replace: 使用后面数组的值替换第一个数组的值, 同名的键名会彼此覆盖,适合自定义配置参数 $arr = ['type'=>'mysql', 'host'=>'localhost', 'username'=>'root', 'password'=>'root']; $arr1 = ['host'=>'127.0.0.1', 'username'=>'admin']; $arr2 = ['username'=>'peter', 'password'=>'123456']; $res =array_replace($arr, $arr1, $arr2); printf('<pre>%s</pre>', print_r($res,true)); echo '<hr>'; // 6. array_intersect: 计算数组的交集 $arr1 = [10, 20, 30, 40, 'php']; $arr2 = [1,'php', 20, 30, 5]; $arr3 = ['a','c', 'php', 30, 10, 20]; // 交集,即返回多个数组中, 都存在的元素 $res = array_intersect($arr1, $arr2, $arr3); // 20, 30, 'php' printf('<pre>%s</pre>', print_r($res,true)); // array_intersect_assoc: 返回数组交集,键名也做比较, echo '<hr>'; // 7. array_diff:返回数组的差集 // 从第一个参数$arr数组中, 去掉在$arr2, $arr3中存在的元素 // 可理解为减法: $arr1 - $arr2 - $arr3 ,最终剩下的是只存在于$arr1中的元素 $res = array_diff($arr1, $arr2, $arr3); printf('<pre>%s</pre>', print_r($res,true)); // 只剩下40 // array_diff_assoc: 返回数组差集,键名也做比较,请同学位自行测试 ``` --- ### 2.8 分割与合并 | 序号 | 函数 | 描述 | | ---- | --------------- | -------------------------------- | | 1 | `array_combine` | 通过合并两个数组来创建一个新数组 | | 2 | `array_merge` | 把一个或多个数组合并为一个数组 | | 3 | `array_chunk` | 将一个数组分割成多个子数组 | 示例: ```php // 分割与合并 // 1. array_combine: 通过合并两个数组(一个是"键数组",一个是"值数组")来创建一个新数组 $keys = ['type', 'host', 'dbname', 'username', 'password']; $values = ['mysql', 'localhost', 'phpedu', 'root', 'root']; $res = array_combine($keys, $values); printf('<pre>%s</pre>', print_r($res,true)); echo '<hr>'; // 2. array_merge($arr1, $arr2,...): 把一个或多个数组合并为一个数组 // 这个功能经常被用在项目配置上, 使用用户自定义配置项覆盖项目默认配置顶 $default= ['host'=>'localhost', 'username'=>'root', 'password'=>'root']; $custom = ['username'=>'admin', 'password'=>'123456']; $res = array_merge($default, $custom); printf('<pre>%s</pre>', print_r($res,true)); echo '<hr>'; // 3. array_chunk`: 将一个数组分割成多个子数组,在海量数据查询时非常实用 // 注意, 这是数据分块, 不是分页, 也不能代替分页查询 $arr = range(1,20); $res = array_chunk($arr, 6); printf('<pre>%s</pre>', print_r($res,true)); ``` --- ### 2.9 自动生成 | 序号 | 函数 | 描述 | | ---- | ----------------- | ---------------------------- | | 1 | `array_fill` | 用给定的值填充数组 | | 2 | `array_fill_keys` | 使用指定的键和值填充数组 | | 3 | `array_pad` | 以指定长度将一个值填充进数组 | 示例: ```php // 自动生成 // 1.array_fill: 用给定的值填充数组 $res = array_fill(2, 5, 'demo'); printf('<pre>%s</pre>', print_r($res, true)); echo '<hr>'; // 2. array_fill_keys: 使用指定的键和值填充数组,注意键名各不相同, 但值是一样的 // 先创建一个键名数组 $keys = ['id', 'name', 'age', 'email']; $res = array_fill_keys($keys, 'demo'); printf('<pre>%s</pre>', print_r($res, true)); echo '<hr>'; // 3. array_pad`: 以指定长度将一个值填充进数组 $arr = ['apple', 'dell', 'thinkpad']; $res = array_pad($arr, 6, 'computer'); printf('<pre>%s</pre>', print_r($res, true)); ``` --- ### 2.10 类型转换 | 序号 | 函数 | 描述 | | ---- | --------- | ---------------------------------------- | | 1 | `list` | 将数组中的值赋予一组变量(类似解构赋值) | | 2 | `implode` | 将数组元素按指定字符拼装成字符串 | | 3 | `explode` | 将字符串分割为数组 | | 4 | `extract` | 将关联数组拆分成变量名值对 | | 5 | `compact` | 将一组变量名值对拼装成一个关联数组键值对 | 示例: ```php // 类型转换 // 1.list: 将数组中的值赋予一组变量(类似解构赋值) // 索引数组转变量 list($id, $name) = [10, 'admin']; printf('$id = %s, $name = %s <br>', $id, $name); // php7+, 支持关联数组元素转变量 list('id'=>$id, 'name'=>$name) = ['id'=>20, 'name'=>'peter']; printf('$id = %s, $name = %s <br>', $id, $name); // 取一部分值 list(,,$email) = [10, 'admin', 'admin@php.cn']; echo $email . '<br>'; echo '<hr>'; // 2. implode: 将数组元素按指定字符拼装成字符串 $arr = ['huawei', 'xiaome', 'apple', 'oppo', 'vivo']; echo implode(', ', $arr); echo '<hr>'; // 3. explode`: 将字符串分割为数组 $str = 'blue, green, yellow, red, coral'; // 注意, 逗号后面要有一个空格, 这样才能与原始字符串对应上 $res = explode(', ', $str); printf('<pre>%s</pre>', print_r($res, true)); echo '<hr>'; // 4. extract: 将关联数组拆分成变量名值对 // 以pdo连接参数为例进行演示 $config = ['type'=>'mysql','host'=>'localhost', 'dbname'=>'phpedu', 'charset'=>'utf8']; extract($config); // 拼装dsn字符串 $dsn = sprintf('%s:host=%s; dbname=%s; charset=%s',$type,$host, $dbname, $charset); echo $dsn , '<br>'; // 连接数据库,先创建数据库phpedu,防止连接失败, 用户名密码采用默认值:root $pdo = new PDO($dsn, 'root', 'root'); var_dump($pdo); echo '<hr>'; // 5. compact: 将一组变量名值对拼装成一个关联数组键值对 $id = 99; $name = 'Peter Zhu'; $job = 'Lecture'; // 传统方式, 手工创建关联数组,将变量值做为元素值填充 $res = ['id'=>$id, 'name'=>$name, 'job'=>$job]; printf('<pre>%s</pre>', print_r($res, true)); // 使用compace()可一步到位 $res = compact('id', 'name', 'job'); printf('<pre>%s</pre>', print_r($res, true)); ``` --- ### 2.11 回调处理 | 序号 | 函数 | 描述 | | ---- | -------------- | ---------------------------------------------- | | 1 | `array_filter` | 用回调函数过滤数组中的单元 | | 2 | `array_map` | 为数组的每个元素应用回调函数 | | 3 | `array_reduce` | 用回调函数迭代地将数组简化为单一的值 | | 4 | `array_walk` | 使用用户自定义函数对数组中的每个元素做回调处理 | 示例: ```php // 数组元素的回调处理 // 1. array_filter: 用回调函数过滤数组中的单元,返回回调执行为true的元素组成的新数组 $arr = [150,'php', true,[4,5,6], (new class {}), [], null, false,'', 0, '0']; // 利用回调只返回运算结果为true元素特征, 可以过滤掉数组中的可转为false的值 // 自动转换为false的值包括但不限于: null, false, 空数组, 空字符串, 0, '0' // 提示: 空对象不能转为false, 空数组可以 // 省略回调参数, 则自动过滤掉数组中可转为false的值,实现过滤空值的效果 $res = array_filter($arr); printf('<pre>%s</pre>', print_r($res,true)); // 自定义回调函数参数, 返回运算结果为true的值组成的数组 $res = array_filter($arr, function($value) { // 只返回标量类型的元素: interger, float, string, boolean // 所以, 被过滤掉的元素类型是array, object, 包括空数组,空对象 return is_scalar($value); }); printf('<pre>%s</pre>', print_r($res,true)); echo '<hr>'; // 2 array_map: 为数组的每个元素应用回调函数,返回回调处理后的所有元素组成的 "新数组" $arr = ['php',[3,4,5], (new class {public $name='电脑';public $price=8888;}), 15, 20]; $res = array_map(function ($item){ switch (gettype($item)) { case 'object': $item = get_object_vars($item); case 'array': $item = implode(', ', $item); } return $item; }, $arr); printf('<pre>%s</pre>', print_r($res,true)); // 同时处理多个数组,例如将一个键名与值的二个数组进行组装 $keys = ['host', 'username', 'password']; $values = ['localhost', 'root', '123456']; // 当然,使用前面学过的: array_combine()可以轻松实现 $res = array_combine($keys, $values); printf('<pre>%s</pre>', print_r($res,true)); // 其实,使用array_map()也可以实现同样功能 $res = array_map(function ($value1, $value2) { return [$value1 => $value2]; }, $keys, $values); printf('<pre>%s</pre>', print_r($res,true)); // 不过, 返回的是一个二维数组, 如果要获取用户名,需要这样做,比较麻烦 echo '用户名: ' . $res[1]['username']; // 下面我们用数组迭代函数实现同样功能来拉平这个数组,模拟array_combine()函数的功能 echo '<hr>'; // 自定义数组迭代处理函数: my_array_reduce($array, $callback, $init=null) // $callback回调中的二个参数 // $prev: 上一次迭代处理的结果,如果是第一次迭代,它的值是第三个参数$init提供的初始值 // $current: 本次需要迭代处理的值 // $init: 可选, 在迭代处理前,或者处理结束后,数组为空时的最后一个结果 function my_array_reduce($array, $callback, $init=null) { // $prev的初始值 $prev = $init; foreach($array as $current){ // 为数组中每一个元素调用迭代回调函数进行处理 $prev = $callback($prev, $current); } // 将最终结果通过前一次迭代变量返回 return $prev; } $result = my_array_reduce($res, function ($prev, $current) { // 获取当前元素的键值 $key = key($current); $value = current($current); // 将键值对拼装成一个元素, 利用$prev,将结果返回 $prev[$key] = $value; return $prev; }); printf('自定义数组迭代函数返回值:<pre>%s</pre>', print_r($result,true)); echo '<hr>'; // 幸运的是, 我们不用自定义数组迭代处理函数, 系统已经为我们预置了 // 3. array_reduce($arr, $callback($prev, $current), $init): 用回调函数迭代地将数组简化为单一的值 // $res: 它是前面array_map()的返回值,是一个二维数组 $res = array_reduce($res, function ($prev, $current) { // 获取当前元素的键值 $key = key($current); $value = current($current); // 将键值对拼装成一个元素, 利用$prev,将结果返回 $prev[$key] = $value; return $prev; }); printf('内置数组迭代函数返回值:<pre>%s</pre>', print_r($res,true)); echo '<hr>'; // 4. array_walk: 使用用户自定义函数对数组中的每个元素做回调处理, 返回布尔值 // array_walk($arr, callback($value, $key), $userdata) // 回调的第一个参数$value,如果设置为引用(&$value),则所做的修改直接作用到原始数组本身 // 如果提供了第三个参数$userdata,则做为回调的第三个参数传入 // 这个函数不受数组内部指针约束, 不论当前指针在哪,都会遍历整个数组 // 该函数主要用于在遍历数组的时候进行一些自定义操作, 例如元素的格式化等, 所以常在回调中使用输出语句 // 例如,将数组元素的值,描红输出 $res = ['id'=>123, 'name'=>'peter', 'email'=>'peter@php.cn']; array_walk($res, function ($value, $key, $color){ printf('[ %s ] => <span style="color:%s">%s</span><br>', $key, $color, $value); }, 'red'); ```