PHP array_unique() 僅支持一維數組。針對二維數組去重,業界沉澱出兩大經典方案:方案一:完全重建索引 (適用於順序無關場景)、方案二:保留原鍵名 (適用於業務依賴鍵名場景)。本文深度對比兩者實現、適用場景、性能差異。
/**
* 二維數組去重:重建 0 基數字索引,不保留原鍵名
* @param array $array2D
* @return array 去重後數組 (數字索引 0,1,2...)
*/
function array_unique_fb($array2D) {
foreach ($array2D as $v) {
$v = join(',', $v); // 降維:子數組 → 字符串
$temp[] = $v;
}
$temp = array_unique($temp); // 一維去重
foreach ($temp as $k => $v) {
$temp[$k] = explode(',', $v); // 重組:字符串 → 子數組
}
return $temp;
}
0, 1, 2... 連續數字'first', 'second') 丟失, 若出現在數據中會導致錯誤拆分/**
* 二維數組去重:保留一級鍵名,按需保留二級鍵結構
* @param array $array2D
* @return array
*/
function array_unique_fb_keep_keys($array2D) {
foreach ($array2D as $k => $v) {
$v = join(',', $v);
$temp[$k] = $v; // 保留一級鍵
}
$temp = array_unique($temp);
foreach ($temp as $k => $v) {
$arr = explode(',', $v);
// 業務特定鍵名映射 (需根據實際結構調整)
$temp2[$k]['id'] = $arr[0];
$temp2[$k]['title'] = $arr[1];
$temp2[$k]['keywords'] = $arr[2];
$temp2[$k]['content'] = $arr[3];
}
return $temp2;
}
'first', 'third')$arr[0] → 'id'),通用性差| 維度 | 方案一:重組法 | 方案二:保留鍵名法 |
|---|---|---|
| 一級鍵保留 | ❌ 重建 0 基索引 | ✅ 保留原鍵名 |
| 二級鍵保留 | ✅ 自動保留 (靠 join/explode 位置對應) | ⚠️ 需硬編碼映射 |
| 代碼通用性 | ✅ 高 (無業務耦合) | ❌ 低 (含具體字段映射) |
| 適用場景 | 數據集合去重、API 返回值清洗 | 配置項去重、主鍵關聯數據去重 |
| 分隔符風險 | ⚠️ 同等風險 | ⚠️ 同等風險 |
| 性能 | 略快 (無鍵名操作) | 略慢 (鍵名保留開銷) |
上述兩方案均使用 join(','),若數據包含逗號會導致 explode 錯誤拆分。生產環境必須使用不可見字符:
$sep = "\x1F"; // Unit Separator (ASCII 31), 極難出現在業務數據中 // 或 $sep = chr(31); // 同義 // 安全版 join/explode $v = join($sep, $v); $arr = explode($sep, $v);
/**
* 通用二維/多維數組去重:serialize 序列化法
* 優勢:無分隔符風險、支持任意嵌套、保留類型、性能優
* @param array $array
* @param bool $keepKeys 是否保留一級鍵
* @return array
*/
function array_unique_multi($array, $keepKeys = false) {
if ($keepKeys) $keys = array_keys($array);
foreach ($array as $k => $v) {
$temp[$k] = serialize($v); // 完美保留結構與類型
}
$temp = array_unique($temp);
foreach ($temp as $k => $v) {
$output[$keepKeys ? $keys[$k] : $k] = unserialize($v);
}
return $output;
}
/**
* 指定字段去重:保留首次出現記錄
* @param array $data
* @param string $field
* @return array
*/
function unique_by_field($data, $field) {
$seen = [];
return array_filter($data, function($item) use ($field, &$seen) {
$val = $item[$field] ?? null;
if ($val === null) return true; // 無該字段不參與去重
if (isset($seen[$val])) return false;
$seen[$val] = true;
return true;
});
}
// 示例:用戶列表按 email 去重
$users = [
['id'=>1, 'email'=>'a@test.com', 'name'=>'Alice'],
['id'=>2, 'email'=>'b@test.com', 'name'=>'Bob'],
['id'=>3, 'email'=>'a@test.com', 'name'=>'Alice2'], // 重複 email
];
print_r(unique_by_field($users, 'email'));
/* 保留 id=1 的記錄 */
keepKeys=truePHP 二維數組去重沒有銀彈,核心取決於業務對鍵名的依賴程度與數據結構複雜度。現代 PHP (7.2+) 可嘗試 array_unique($arr, SORT_REGULAR) 直接支持多維 (但不保留鍵)。生產環境建議:封裝工具類統一入口,內部路由至 serialize 版或字段去重版,棄用分隔符方案。