PHP数组怎么移除重复值保留顺序_array_unique改进技巧【技巧】

7次阅读

array_unique() 默认重排索引且不保留原始键名,需手动遍历去重以保键保序;sort_regular 可区分类型,多维数组须序列化后去重。

PHP数组怎么移除重复值保留顺序_array_unique改进技巧【技巧】

array_unique() 保留顺序但键名错乱?

array_unique() 默认会重排索引,导致数字键变成 0,1,2…,而你可能依赖原始键(比如从数据库查出的带 ID 的关联数组)。这不是 bug,是设计如此——它只保证值唯一,不承诺键结构。

解决方法很简单:用 array_values() 重排索引(如果你真需要连续数字键),或更常见的是用 array_merge() 强制重置键:

$arr = ['a' => 1, 'b' => 2, 'c' => 1]; $result = array_merge(array_unique($arr)); // $result['a'] 不存在了,键变成 0=>1, 1=>2

但注意:array_merge() 对关联键无效,它只对数字键“重编号”,所以真正想保留原始键名(如 'a''b'),就得手动遍历去重。

手写去重保留原始键和顺序的通用写法

php 没有内置函数直接支持“去重+保键+保序”,得自己控制逻辑。核心是用一个临时数组记录已见的值,跳过重复项。

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

  • foreach 遍历原数组,检查值是否已在 $seen
  • 没出现过就写入结果数组,并在 $seen 标记该值
  • 注意:浮点数、布尔、NULL 的比较要小心,in_array($v, $seen, true) 效率低,改用 isset($seen[$v]) 不行(因为键只能是字符串或整数)
  • 稳妥做法是把值转成字符串再哈希,或直接用 !in_array($v, $seen, true) + 小数组;大数组建议用 array_flip() 预处理
$arr = ['a'=>1, 'b'=>2, 'c'=>1, 'd'=>3]; $seen = []; $result = []; foreach ($arr as $k => $v) {     if (!in_array($v, $seen, true)) {         $result[$k] = $v;         $seen[] = $v;     } }

array_unique()SORT_StringSORT_REGULAR 差在哪

默认行为是 SORT_STRING,会把所有值转成字符串比较,导致 0'0' 被认为相同;而 SORT_REGULAR 用 PHP 原生类型比较规则,0 === '0' 是 false,所以能区分。

  • 多数情况该用 SORT_REGULAR,尤其数组含混合类型(int/string/bool
  • SORT_STRING 可能引发意外合并,比如 [0, '0', false]array_unique() 后只剩一个元素
  • 性能上差别不大,但语义清晰更重要
$arr = [0, '0', false]; var_dump(array_unique($arr));           // [0] var_dump(array_unique($arr, SORT_REGULAR)); // [0, '0', false]

多维数组怎么去重?array_unique() 不支持

array_unique() 只能处理一维,遇到二维数组(如 [['id'=>1,'name'=>'A'], ['id'=>1,'name'=>'A']])会报 warning 并返回原数组。

必须先序列化每行再比对,或者用 json_encode() 生成唯一标识:

  • json_encode($row, JSON_UNESCAPED_UNICODE) 更可靠,避免中文编码问题
  • 记得加 JSON_UNESCAPED_UNICODE,否则中文变 uXXXX,影响可读性和调试
  • 如果数组含资源、闭包循环引用,json_encode() 会失败,此时只能用 serialize()(但结果不可读,且版本兼容性差)
$rows = [['id'=>1,'n'=>'A'], ['id'=>1,'n'=>'A']]; $seen = []; $result = []; foreach ($rows as $k => $row) {     $key = json_encode($row, JSON_UNESCAPED_UNICODE);     if (!isset($seen[$key])) {         $result[] = $row;         $seen[$key] = true;     } }

复杂点在于:嵌套结构、浮点精度、NaN、对象等没法靠简单序列化搞定,这种场景建议提前规范数据结构,或用专门的库做 deep-compare。

text=ZqhQzanResources