首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 陣列集合運算完全指南:合併、交集、差集、array_merge/array_intersect/array_diff 深度解析

     編輯:PHP 相關知識

前言:陣列集合運算是資料處理的基石

在處理多組資料時,常需進行合併 (Union)、交集、差集等集合運算。PHP 提供 array_merge()、array_intersect()、array_diff() 等函式,但其行為在**字串鍵名 vs 數值鍵名**、**重複值處理**、**多陣列參數**等細節上有顯著差異。本文深度解析各函式特性與最佳實踐。

陣列合併:array_merge vs + 運算子

array_merge() 行為

  • 數值鍵名:重新索引 (0, 1, 2...),不保留原鍵名
  • 字串鍵名:後者覆蓋前者
  • 多陣列:依序處理,後面陣列優先權較高

+ 運算子行為

  • 數值鍵名:先出現者優先,不重新索引
  • 字串鍵名:先出現者優先,不覆蓋
  • 只接受兩個陣列

對比範例

<?php
$a = [1 => 'a', 'b', 'c'];        // [1=>'a', 0=>'b', 1=>'c'] 實際為 [1=>'a', 0=>'b', 1=>'c'] → 最後 1=>'c'
$b = [1 => 'aa', 2, 'c'];         // [1=>'aa', 0=>2, 1=>'c'] → 最後 1=>'c'

// array_merge: 數值鍵重新索引,字串鍵後者勝出
$merged = array_merge($a, $b);
/* 結果:
[0] => 'a'   (原 $a[1])
[1] => 'b'   (原 $a[0])
[2] => 'c'   (原 $a[1] 即 'c')
[3] => 'aa'  (原 $b[1])
[4] => 2     (原 $b[0])
[5] => 'c'   (原 $b[1] 即 'c')
*/

// + 運算子: 先勝出,保留原鍵名
$union = $a + $b;
/* 結果:
[1] => 'a'   ($a[1] 勝出)
[0] => 'b'   ($a[0])
[2] => 2     ($b[0] 數值鍵 0 未在 $a 中)
*/
?>

字串鍵名對比

<?php
$a2 = ['str' => 'a', 'b', 'c'];
$b2 = ['str' => 'aa', 2, 'c'];

$merged2 = array_merge($a2, $b2);
// ['str' => 'aa', 0 => 'b', 1 => 'c', 2 => 2, 3 => 'c']  // 'str' 後者勝出

$union2 = $a2 + $b2;
// ['str' => 'a', 0 => 'b', 1 => 'c']  // 'str' 先勝出
?>

去重合併:array_unique()

<?php
$merged = array_merge($a, $b);
$unique = array_unique($merged); // 移除重複值,保留第一次出現的鍵名
// 注意:array_unique 保留鍵名,可能導致索引不連續
$reindexed = array_values($unique); // 重新索引 0..n
?>

陣列交集:array_intersect 系列

array_intersect() - 值交集 (保留鍵名)

<?php
$a = ['jpg', 'png', 'gif', 'bmp'];
$b = ['JPG', 'txt', 'docx', 'bmp'];

$intersection = array_intersect($a, $b);
// 結果: [3 => 'bmp']  (大小寫敏感,只有 'bmp' 完全相同)
?>

不區分大小寫交集:array_uintersect / array_intersect_uassoc

<?php
// 方法 1: 先統一大小寫再交集
$intersection2 = array_intersect(
    array_map('strtolower', $a),
    array_map('strtolower', $b)
);
// 結果: [0 => 'jpg', 3 => 'bmp']

// 方法 2: 自訂比較函式 (保留原鍵名與原值)
$intersection3 = array_uintersect($a, $b, function($x, $y) {
    return strcasecmp($x, $y);
});
// 結果: [0 => 'jpg', 3 => 'bmp'] 保留原始大小寫
?>

鍵名+值雙重交集:array_intersect_assoc / array_intersect_uassoc

<?php
$a = ['a' => 1, 'b' => 2, 'c' => 3];
$b = ['a' => 1, 'b' => 99, 'd' => 4];

array_intersect($a, $b);      // 值交集: ['a'=>1, 'c'=>3] (值 1 和 3 都在 $b 中)
array_intersect_assoc($a, $b); // 鍵值雙重交集: ['a'=>1] (只有 'a'=>1 完全相同)
?>

陣列差集:array_diff 系列

array_diff() - 值差集 (在第一個陣列中,但不在其他陣列中)

<?php
$old = ['jpg', 'png', 'gif', 'bmp'];
$new = ['JPG', 'txt', 'docx', 'bmp'];

$diff = array_diff($old, $new);
// 結果: [0 => 'jpg', 1 => 'png', 2 => 'gif']  (大小寫敏感,'jpg' != 'JPG')
?>

不區分大小寫差集

<?php
$diff2 = array_diff(
    array_map('strtolower', $old),
    array_map('strtolower', $new)
);
// 結果: [0 => 'jpg', 1 => 'png', 2 => 'gif']

// 保留原值大小寫的差集
$diff3 = array_udiff($old, $new, function($x, $y) {
    return strcasecmp($x, $y);
});
// 結果: [0 => 'jpg', 1 => 'png', 2 => 'gif']
?>

鍵名+值雙重差集:array_diff_assoc / array_diff_uassoc

<?php
$a = ['a' => 1, 'b' => 2, 'c' => 3];
$b = ['a' => 1, 'b' => 99, 'd' => 4];

array_diff($a, $b);        // 值差集: ['b'=>2, 'c'=>3] (值 2,3 不在 $b)
array_diff_assoc($a, $b);  // 鍵值雙重差集: ['b'=>2, 'c'=>3] ('b'=>2 不同, 'c' 不在 $b)
?>

多陣列運算

所有上述函式均支援 **3 個或更多陣列參數**:

<?php
$a = [1, 2, 3, 4, 5];
$b = [3, 4, 5, 6, 7];
$c = [5, 6, 7, 8, 9];

array_merge($a, $b, $c);      // 依序合併
array_intersect($a, $b, $c);  // 三者共同擁有的值: [5]
array_diff($a, $b, $c);       // 在 $a 但不在 $b 和 $c: [1, 2]
?>

效能與記憶體考量

操作時間複雜度空間複雜度備註
array_mergeO(N)O(N)建立新陣列
array_intersectO(N×M)O(min(N,M))內部使用雜湊表查找
array_diffO(N×M)O(N)建立查找表
array_uniqueO(N)O(N)排序後去重

大量資料優化策略

  • 預先建立查找表:$lookup = array_flip($largeArray); 然後 isset($lookup[$value]) O(1) 查找
  • 避免巢狀迴圈:善用內建函式,底層已優化
  • 分塊處理:超大陣列使用 array_chunk() 分批
  • 資料庫層面運算:SQL UNION/INTERSECT/EXCEPT 或 JOIN 通常更高效

實戰應用場景

場景一:權限系統 - 用戶角色權限合併

<?php
$userRoles = ['user', 'editor'];
$groupRoles = ['editor', 'admin'];
$explicitPermissions = ['publish', 'delete'];

// 合併所有權限 (去重)
$allPermissions = array_unique(array_merge($userRoles, $groupRoles, $explicitPermissions));
// ['user', 'editor', 'admin', 'publish', 'delete']

// 檢查是否擁有特定權限
function hasPermission($permissions, $required) {
    return in_array($required, $permissions, true); // 嚴格比較
}
?>

場景二:資料同步 - 新舊資料比對

<?php
$oldIds = [1, 2, 3, 4, 5];      // 資料庫現有 ID
$newIds = [3, 4, 5, 6, 7];      // API 回傳 ID

$toDelete = array_diff($oldIds, $newIds); // [1, 2] 需刪除
$toInsert = array_diff($newIds, $oldIds); // [6, 7] 需新增
$toUpdate = array_intersect($oldIds, $newIds); // [3, 4, 5] 需更新
?>

場景三:表單驗證 - 必填欄位檢查

<?php
$required = ['name', 'email', 'phone', 'address'];
$submitted = array_keys($_POST); // 實際提交的欄位

$missing = array_diff($required, $submitted);
if ($missing) {
    throw new Exception('缺少必填欄位: ' . implode(', ', $missing));
}
?>

函式選擇決策表

需求推薦函式關鍵行為
合併多個陣列,數值鍵重新索引array_merge()後者覆蓋字串鍵
合併兩個陣列,保留原鍵名,先勝出$a + $b不重新索引
找出多個陣列共同的值array_intersect()保留第一個陣列鍵名
找出共同的鍵值對array_intersect_assoc()鍵+值都相同
找出在 A 但不在 B 的值array_diff()保留 A 的鍵名
找出在 A 但不在 B 的鍵值對array_diff_assoc()鍵+值都不同
不區分大小寫比較array_uintersect / array_udiff自訂比較函式
移除重複值array_unique()保留第一次出現的鍵名

總結

  1. array_merge vs +:理解數值鍵重新索引與字串鍵覆蓋/優先的差異,根據語意選擇
  2. 交集/差集:預設比較**值**,需鍵值雙重比較用 _assoc 尾綴函式
  3. 大小寫敏感:預設敏感,不敏感需用 array_map('strtolower') 或 _u 系列自訂比較
  4. 多陣列支援:所有集合函式均支援 3+ 參數
  5. 效能:大量資料優先考慮資料庫運算或雜湊表查找

熟練掌握陣列集合運算,能以宣告式程式碼替代複雜的巢狀迴圈邏輯,提升可讀性與維護性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved