# 常用數組函數大全
[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');
```