| 常數 | 比較模式 | 說明 |
SORT_STRING | 字串比較 | 預設。100 === '100' 為真。 |
SORT_REGULAR | 標準比較 (不轉型) | 推薦。100 !== '100',類型也要相同。 |
SORT_NUMERIC | 數值比較 | '100' == 100 為真。 |
SORT_LOCALE_STRING | 當地化字串比較 | 依 setlocale()。 |
場景一:一維陣列 - 保留原鍵名
$arr = ['a' => 1, 'b' => 2, 'c' => 1, 'd' => 3];
$unique = array_unique($arr, SORT_REGULAR);
// 結果:['a'=>1, 'b'=>2, 'd'=>3] (字串鍵保留)
$arr = [10, 20, 10, 30];
$unique = array_unique($arr, SORT_REGULAR);
// 結果:[0=>10, 1=>20, 3=>30] (數字鍵保留第一個出現的鍵)
場景二:多維陣列去重 (核心痛點)
array_unique 無法直接處理多維陣列 (會觸發 Array to string conversion Notice)。
方案 A:序列化比較 (通用、保留結構)
function arrayUniqueMulti(array $arr): array {
$serialized = array_map('serialize', $arr);
$unique = array_unique($serialized, SORT_REGULAR);
return array_map('unserialize', $unique);
}
$data = [
['id'=>1, 'name'=>'A'],
['id'=>2, 'name'=>'B'],
['id'=>1, 'name'=>'A'], // 重複
['id'=>3, 'name'=>'C'],
];
print_r(arrayUniqueMulti(data));
// 保留鍵 0,1,3
方案 B:JSON 編碼比較 (效能較好、需注意編碼一致性)
function arrayUniqueMultiJson(array $arr): array {
$encoded = array_map(fn($v) => json_encode($v, JSON_UNESCAPED_UNICODE|JSON_SORT_KEYS), $arr);
$unique = array_unique($encoded, SORT_REGULAR);
return array_map('json_decode', $unique, [true]); // true = 關聯陣列
}
方案 C:自定義比較鍵 (大數據高效)
function arrayUniqueByKey(array $arr, string $key): array {
$seen = [];
return array_filter($arr, function($item) use ($key, &$seen) {
$val = $item[$key] ?? null;
if (isset($seen[$val])) return false;
$seen[$val] = true;
return true;
});
}
$data = [
['id'=>1, 'name'=>'A', 'email'=>'a@x.com'],
['id'=>2, 'name'=>'B', 'email'=>'b@x.com'],
['id'=>1, 'name'=>'A', 'email'=>'a2@x.com'], // id 重複
];
print_r(arrayUniqueByKey($data, 'id'));
// 保留第一筆 id=1
場景三:大陣列效能優化 (10萬+ 元素)
array_unique 內部排序複雜度 O(n log n)。若只需「保留第一次出現」,用 array_flip 雙翻轉 O(n):
function arrayUniqueFast(array $arr): array {
// 僅適用值為純量 (可作鍵) 的陣列
return array_flip(array_flip($arr));
}
// 測試
$arr = range(1, 100000);
$arr = array_merge($arr, $arr); // 20萬元素,50% 重複
$t = microtime(true); array_unique($arr); echo "array_unique: " . (microtime(true)-$t) . "s\n";
$t = microtime(true); arrayUniqueFast($arr); echo "flip*2: " . (microtime(true)-$t) . "s\n";
// 典型輸出:array_unique: 0.045s, flip*2: 0.008s (快 5-6 倍)
限制:值必須為 int/float/string/bool/null (可作陣列鍵),且會重新索引數字鍵 (0,1,2...)。
場景四:物件陣列去重
class User { public int $id; public string $name; }
$users = [
new User(1, 'A'),
new User(2, 'B'),
new User(1, 'A'), // 同屬性值
];
// 方案:spl_object_id (PHP 7.2+) 比較實例身份
$unique = [];
$ids = [];
foreach ($users as $u) {
$oid = spl_object_id($u);
if (!isset($ids[$oid])) {
$ids[$oid] = true;
$unique[] = $u;
}
}
// 方案:自定義比較邏輯 (如比較 id 屬性)
$unique = [];
$seenIds = [];
foreach ($users as $u) {
if (!isset($seenIds[$u->id])) {
$seenIds[$u->id] = true;
$unique[] = $u;
}
}
常見陷阱總結
- 預設字串比較:
100 == '100' 導致類型不同但值相同被視為重複 → 永遠加 SORT_REGULAR。
- 多維陣列報 Notice:必須序列化/JSON 編碼後比較。
- 鍵名重置:
array_unique 保留字串鍵,但數字鍵會保留第一個出現的鍵 (非連續)。若需連續索引 → array_values()。
- 大陣列記憶體:序列化/JSON 會產生大量臨時字串,超大陣列考慮分塊處理或資料庫
DISTINCT。
- 物件比較:預設比較屬性值 (如同陣列),但
SORT_REGULAR 可能不生效,建議自定義邏輯。
最佳實踐速查表
| 場景 | 推薦方案 | 關鍵點 |
| 一維純量陣列、保留鍵 | array_unique($arr, SORT_REGULAR) | 加 SORT_REGULAR |
| 一維純量、極大陣列、可重置鍵 | array_flip(array_flip($arr)) | O(n) 極快 |
| 多維陣列、完整結構比較 | array_map('unserialize', array_unique(array_map('serialize', $arr), SORT_REGULAR)) | 通用、保留鍵 |
| 多維陣列、指定欄位去重 | arrayUniqueByKey($arr, 'id') | O(n)、業務語義清晰 |
| 物件陣列、比較屬性 | 自定義循環 + 看見集合 | 可控、效能好 |
去重看似簡單,選對工具與參數能省下大量 CPU 與記憶體。記住「SORT_REGULAR 是預設陷阱的解藥」、「多維必須序列化」、「大陣列用翻轉法」三大原則,應對 99% 場景綽綽有餘。
- 上一篇文章: PHP Session 存入資料庫完整實現:自定義處理器、分佈式會話與安全加固
- 下一篇文章: PHP 獲取 Bing 每日壁紙並直接輸出圖片流
Copyright ©
程式碼之家 All Rights Reserved