array_unique默认保留首次出现顺序,仅移除后续重复项;键名保持原样导致print_r显示错觉,实际foreach遍历顺序不变;需连续索引时才用array_values重置键。

array_unique 默认就保留首次出现的顺序
array_unique() 本身不会打乱元素在原数组中的相对位置——它只移除后续重复项,留下第一次出现的那个。所以对索引数组(如 [0=>'a', 1=>'b', 2=>'a', 3=>'c']),结果一定是 [0=>'a', 1=>'b', 3=>'c'],顺序没变,只是键可能“跳号”。
常见误解是以为顺序被重排了,其实是键名保留导致 print_r 显示不连续,让人误判“顺序乱了”。实际遍历时用 foreach,顺序仍是 a → b → c。
- 不需要额外排序或
ksort() - 不要用
array_values()再包裹——这会丢掉原始键,且不改变值顺序,纯属多此一举 - 若你观察到顺序异常,大概率是原数组键名本身就是乱序的(比如从数据库 fetch 出来时用了
ORDER BY id DESC)
为什么 print_r 看起来“顺序不对”?
因为 array_unique() 保留原始键名,而索引数组的键名常被误当作“顺序标识”。例如:
$arr = [2 => 'x', 0 => 'y', 1 => 'x', 3 => 'z']; $result = array_unique($arr); // 输出:Array ( [2] => x [0] => y [3] => z )
这里 'y' 在 'x' 之后被遍历到,但键 0 比 2 小,print_r 按键升序显示,造成“y 跑前面了”的错觉。但真实遍历顺序(foreach)仍是按定义顺序:key 2 → key 0 → key 3。
立即学习“PHP免费学习笔记(深入)”;
- 验证方式:用
foreach ($result as $v) echo "$v ";,输出是x y z - 真正影响顺序的是数组定义时的键插入顺序,不是键数值大小
- PHP 7.4+ 中,关联数组的遍历顺序严格等于插入顺序,这点和索引数组一致
需要连续数字索引时,必须显式调用 array_values()
如果你后续要依赖 $result[0]、$result[1] 这样的下标访问,或者要 json_encode 成标准 JSON 数组(而非对象),就必须重置键:
$cleaned = array_values(array_unique($arr));
注意这不是为了“保序”,而是为了“保索引结构”。array_values() 不改变值顺序,只把键强行变成 0,1,2...。
- 性能上几乎无开销,O(n)
- 不要写成
array_values($arr) → array_unique(),那样会先丢键再处理,失去“首次出现”语义 - 如果原数组是关联数组(含字符串键),
array_values()是唯一安全的重索引方式;array_merge()或强制类型转换((array))不可靠
去重后顺序异常?先检查是否用了 SORT_STRING 等标志
array_unique() 第二个参数会影响内部比较逻辑,间接干扰“首次出现”的判定边界:
-
SORT_REGULAR(默认):松散比较,1 == '1'→ 视为重复 -
SORT_STRING:强制转字符串比较,'1' !== '1'?不,但1变成'1'后与'1'相同 → 仍重复;真正区别在null、false、''等值 - 错误用法:
array_unique($arr, SORT_NUMERIC)遇到字符串会转成0,导致意外合并
如果你发现本该保留的项被删了,或者顺序“跳着走”,优先检查是否传了非默认的 $sort_flag,并确认所有元素类型是否预期一致。
最稳妥的做法:不加第二个参数,除非你明确需要类型敏感比较;有混合类型时,先统一 cast 再去重。



















