一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

PHP函数array_unique对多维数组失效的解决方案:去重算法

时间:2026-07-12 09:12:03 编辑:袖梨 来源:一聚教程网

array_unique对多维数组无效,因其内部用==比较数组失败而静默保留原数组;推荐serialize+array_unique组合去重,或按字段用array_filter+$seen哈希表高效处理。

array_unique对多维数组直接调用会返回原数组

它根本不会去重,也不报错,只是静默跳过所有子数组——因为 PHP 内部尝试用 == 比较两个数组时失败,最终把整个子数组当“不可比”处理,原样保留。你看到的“没变化”,不是函数卡住,而是设计如此。

常见错误现象:array_unique([['id'=>1], ['id'=>1]]) 返回原数组;array_unique($multi, SORT_REGULAR) 也无效;PHP 8.3 依然不支持。

  • 别指望加 $flags 参数能起作用——多维数组本身就不在 array_unique 的支持范围内
  • 如果数组里混有 null、对象或资源,还会触发 Warning: Array to string conversion
  • 错误日志里可能只显示 “Array to string conversion”,但实际是去重逻辑被绕过了

用 serialize + array_unique 是最简方案

把每个子数组转成唯一字符串再比,绕过类型限制。这是目前最通用、兼容性最好的做法,PHP 5.6 到 8.3 全支持。

示例代码:

立即学习“PHP免费学习笔记(深入)”;

$multi = [['id'=>1,'name'=>'Alice'], ['id'=>1,'name'=>'Alice'], ['id'=>2,'name'=>'Bob']];$unique = array_map('unserialize', array_unique(array_map('serialize', $multi)));
  • array_map('serialize', $multi) 把每个子数组变成字符串,如 a:2:{s:2:"id";i:1;s:4:"name";s:5:"Alice";}
  • array_unique 对这些字符串去重,天然支持
  • array_map('unserialize', ...) 恢复成原始结构,键名和类型都保留
  • 注意:如果子数组含资源、闭包或某些不可序列化对象,serialize() 会失败,得提前过滤

按指定字段去重(比如只看 'email' 或 'id')

当你要的是“按某字段唯一”,而不是“整个子数组完全一致”时,serialize 就过度了。这时用 array_filter + $seen 哈希表更精准、更快。

示例(去重邮箱,忽略大小写):

$users = [['email'=>'[email protected]'], ['email'=>'[email protected]'], ['email'=>'[email protected]']];$seen = [];$unique = array_filter($users, function($u) use (&$seen) {    $key = strtolower($u['email']);    if (isset($seen[$key])) return false;    $seen[$key] = true;    return true;});
  • 必须用 &$seen 引用传递,否则每次回调都是空数组
  • isset($seen[$key]) 而不是 in_array($key, $seen),避免 O(n) 查找拖慢大数组
  • 若需连续数字索引,最后加 array_values($unique)
  • 字段不存在时会触发 Notice,建议先用 isset($u['email'])array_key_exists 防御

大数据量时性能差异明显

10 万条记录下,serialize + array_unique 比手写 foreach + isset 慢 2–3 倍——前者要三次完整遍历(serialize、unique、unserialize),后者一次搞定。

  • 纯数值/字符串 ID 去重,直接用:$seen = []; $result = []; foreach ($arr as $item) { if (!isset($seen[$item['id']])) { $seen[$item['id']] = true; $result[] = $item; } }
  • 字段值可能为 null 或布尔型?不能直接当数组键,改用 $key = serialize($item['field'])
  • 从数据库查出来的数据,常带字符串数字(如 '1'1),array_unique 默认松散比较会误判,手写逻辑可统一转类型再比

真正麻烦的从来不是怎么写,而是你是否意识到:array_unique 的“失效”,往往是因为你传给它的根本就不是它能处理的东西。

热门栏目