PHP多维数组去重不能直接用array_unique(),因其仅支持一维数组;推荐按指定字段去重(如array_column+array_intersect_key),或全字段严格去重时用serialize+array_keys,但需注意浮点数、键序等限制。

PHP多维数组去重不能用 array_unique() 直接处理
array_unique() 默认只对一维数组有效,传入多维数组会报 Warning:“Array to string conversion”,并返回原数组(PHP 7+)或空数组(旧版本)。这是因为它的底层比较逻辑依赖字符串哈希,而数组无法直接转为有意义的唯一字符串。
常见错误写法:array_unique($arr, SORT_REGULAR) 看似能用,但仅在 PHP 7.2+ 中对关联多维数组“勉强可用”,且有严重限制:它要求所有子数组结构完全一致(键名、顺序、嵌套深度),否则仍可能漏判或误判。
实操建议:
- 若子数组是简单关联结构(如
['id' => 1, 'name' => 'a']),优先用array_column()提取关键字段做索引去重 - 若需全字段严格比对,必须手动序列化 + 去重 + 反序列化,但要注意
serialize()对浮点数精度、对象、资源等不安全 - 避免用
json_encode()替代serialize()—— 键名顺序不同会导致 JSON 字符串不同(如['a'=>1,'b'=>2]和['b'=>2,'a'=>1]),造成误判
按指定字段去重(推荐:用 array_column() + array_keys())
这是最常用、性能好、可读性强的方案,适用于“以某个字段(如 id 或 email)为唯一依据”的场景。
立即学习“PHP免费学习笔记(深入)”;
示例:去重用户数组,保留第一个出现的 id 相同的项
$users = [
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
['id' => 1, 'name' => 'Alicia'], // 重复 id
];
$ids = array_column($users, 'id');
$unique_users = array_values(array_intersect_key($users, array_unique($ids)));
关键点:
-
array_column($users, 'id')提取所有id值成一维数组 -
array_unique($ids)去重后保留首次出现的键(即原始索引) -
array_intersect_key($users, ...)按键名筛选原数组,自然保留首次出现项 -
array_values()重置数字索引,避免稀疏数组
全字段严格去重(用 serialize() + array_keys())
当必须确保整个子数组内容完全一致才视为重复时(比如配置项、嵌套参数),只能走序列化路径。但要注意:浮点数、NaN、对象、闭包、资源句柄无法安全序列化,生产环境慎用。
示例:
$data = [
['a' => 1, 'b' => ['x' => 2]],
['a' => 1, 'b' => ['x' => 2]], // 完全相同
['a' => 1, 'b' => ['x' => 3]],
];
$serialized = array_map('serialize', $data);
$unique_serialized = array_keys(array_unique($serialized));
$unique_data = array_intersect_key($data, array_flip($unique_serialized));
注意:
- 不要用
array_map('json_encode', $data)—— 键序不保证,json_encode(['b'=>1,'a'=>2]) !== json_encode(['a'=>2,'b'=>1]) - PHP 8.2+ 引入
array_is_list()可辅助判断是否为纯数字索引数组,但不影响去重逻辑 - 大数据量时,
serialize()+array_unique()会显著增加内存占用,建议分块处理
嵌套更深的数组(如三维)要先扁平化再处理?
不需要强行扁平化。真正的问题是:你到底想按哪一层去重?多数情况下,重复发生在“同级子数组”之间(即二维层面),三维只是子数组内部结构更复杂而已。
比如:[ ['user'=>['id'=>1]], ['user'=>['id'=>1]] ],重复的是外层数组项,不是 user 内部。此时仍适用上文的 serialize() 方案(对整个外层元素序列化),而不是试图提取 $arr[0]['user']['id']。
如果真要按深层字段(如 $item['profile']['contact']['email'])去重,就写个循环提取路径值:
$emails = [];
foreach ($data as $k => $item) {
$email = $item['profile']['contact']['email'] ?? null;
if ($email && !in_array($email, $emails)) {
$emails[] = $email;
$unique[] = $item;
}
}
这种写法可控、易调试,比通用函数更可靠——因为多维数组的“重复定义”本身就没有标准答案,取决于你的业务逻辑。
真正容易被忽略的点:没有“通用安全的多维数组去重函数”。每次都要先明确“什么是重复”,再选方法。用错前提,再短的代码也是错的。



















