← PHP uksort函数详解:用自定义回调按数组键名排序 PHP array_unshift函数详解:数组头部插入元素与键名重建机制 →

PHP array_unique函数详解:数组去重的排序标志与键名保留机制

著
原创 2026-10-09 PHP 已有人查阅

一、函数定位与核心机制

array_unique是PHP内置的数组处理函数,从PHP4.0.1开始提供。它的作用是把数组中重复的值去掉,返回一个过滤后的新数组。

这里有几个关键点需要先理清:

  • 去重针对的是值,不是键名。函数只关心元素的值是否重复,键名不参与重复判断

  • 保留首次出现的元素。多个相同值出现时,第一个被保留,后续的被丢弃

  • 键名会被保留。结果数组中保留的是被保留元素的原始键名,不是重新索引的连续数字

  • 返回新数组。原数组不被修改,结果是一个新的数组变量

第四点很重要。array_unique和uksort不同,它不传引用,不修改原数组,而是返回一个新数组。写代码时可以放心地$result=array_unique($input);,原数组$input保持不变。

语法结构

array array_unique(array $array, int $sort_flags = SORT_STRING): array

参数说明:

参数 是否必需 说明
array 必需 输入数组
sort_flags 可选 排序标志,决定值的比较规则,默认SORT_STRING

sort_flags的四种取值

第二个参数决定去重时用什么规则来判定「两个值是否相等」:

标志 比较规则 典型用途
SORT_REGULAR 按PHP常规规则比较 混合类型数组
SORT_NUMERIC 按数值比较 数字数组
SORT_STRING 按字符串比较(默认) 字符串数组
SORT_LOCALE_STRING 按当前区域设置的字符串规则比较 多语言场景

默认值是SORT_STRING,意味着即使数组里是数字,也会先转成字符串再比较。这一点在数字数组去重时容易踩坑,后面会展开。

二、比较规则的实际差异

用一个例子说明SORT_STRING和SORT_NUMERIC的区别:

$data = array("1", "01", 1, 1.0);
print_r(array_unique($data, SORT_STRING));

用SORT_STRING时,"1"、"01"、1、1.0都转成字符串比较:"1"、"01"、"1"、"1"。结果保留"1"和"01",因为"1"和"01"字符串不相等。

换成SORT_NUMERIC:

print_r(array_unique($data, SORT_NUMERIC));

四个值数值上都等于1,结果只保留第一个"1"。

这个差异在项目中影响很大。从表单接收的数据、从数据库读出的数据,类型可能不统一。如果用默认的SORT_STRING,字符串"1"和整数1会被当作不同值保留下来,去重不彻底。如果业务上认为它们相等,就得显式指定SORT_NUMERIC或SORT_REGULAR。

个人经验:在用户标签去重场景里,标签ID从不同接口返回,有的接口给字符串、有的给整数。一开始用默认参数,结果同一个标签出现两次,一次是"12"一次是12。排查了半天才定位到是sort_flags的问题。后来统一在去重前用array_map做类型转换,或者显式传SORT_REGULAR,问题就解决了。

三、键名保留机制

array_unique保留被保留元素的原始键名,不重新索引。这一点和很多人的直觉不同。

$lang = array('java', 'php', 'java', 'python', 'html');
$result = array_unique($lang);
print_r($result);

输出:

Array
(
    [0] => java
    [1] => php
    [3] => python
    [4] => html
)

键名2缺失,因为索引2的java和索引0的java重复,被丢弃了。结果数组的键名是0、1、3、4,不连续。

如果后续逻辑依赖连续的键名(比如用for循环遍历、用json_encode输出成数组格式),需要手动用array_values重新索引:

$result = array_values(array_unique($lang));

这一点在返回JSON给前端时特别重要。如果不去重后重新索引,json_encode会把结果输出成对象而不是数组,前端拿到的数据结构会变。

四、关联数组的去重行为

对关联数组去重时,键名会保留,但重复值的判断只看值。

$news = array("a" => "zee", "b" => "zee", "c" => "aajtak", "d" => "ndtv");
print_r(array_unique($news));

输出:

Array
(
    [a] => zee
    [c] => aajtak
    [d] => ndtv
)

键名a和b的值都是zee,保留先出现的a,b被丢弃。键名c和d的值不重复,全部保留。

这里有一个值得注意的场景:如果两个元素的键名相同但值不同,在PHP数组里这本身就不可能出现(后写的会覆盖先写的)。所以array_unique处理的是值层面的重复。

五、项目实战示例

示例一:字符串数组去重

<?php
$lang = array('java', 'php', 'java', 'python', 'html');
$result = array_unique($lang);
print_r($result);

输出:

Array
(
    [0] => java
    [1] => php
    [3] => python
    [4] => html
)

键名2的java和键名0重复,被丢弃,结果键名不连续。

示例二:关联数组去重

<?php
$singer = array("a" => "abhijeet", "b" => "arijit", "c" => "abhijeet");
print_r(array_unique($singer));

输出:

Array
(
    [a] => abhijeet
    [b] => arijit
)

键名a和c的值都是abhijeet,保留先出现的a,c被丢弃。

示例三:数字字符串与整数的混合去重

<?php
$laptop = array("a" => "dell", 0 => "hp", "b" => "dell", 1 => "lenovo", 2 => "hp");
$result = array_unique($laptop);
print_r($result);

输出:

Array
(
    [a] => dell
    [0] => hp
    [1] => lenovo
)

dell在键名a和b各出现一次,保留a。hp在键名0和2各出现一次,保留0。lenovo不重复,保留。结果键名是a、0、1,混合了字符串和数字。

示例四:去重后重新索引

<?php
$tags = array("php", "mysql", "php", "redis", "mysql");
$result = array_values(array_unique($tags));
print_r($result);

输出:

Array
(
    [0] => php
    [1] => mysql
    [2] => redis
)

用array_values把键名重新索引成0、1、2,方便后续用for循环或输出成JSON数组。

示例五:数字数组用SORT_NUMERIC

<?php
$ids = array("12", 12, "012", 12.0);
print_r(array_unique($ids, SORT_NUMERIC));

输出:

Array
(
    [0] => 12
)

四个值数值上都等于12,用SORT_NUMERIC只保留第一个。如果换成默认的SORT_STRING,"12"、"12"、"012"、"12"中"012"和"12"字符串不相等,会保留两个元素。

六、容易踩的坑

默认SORT_STRING导致的类型误判。字符串"1"和整数1在默认规则下转成字符串后相等,但字符串"01"和"1"不相等。如果业务上认为它们相同,需要显式指定sort_flags。

键名不连续影响后续逻辑。去重后键名保留原始索引,可能出现0、1、3、4这样的跳号。用for循环遍历会漏元素,用json_encode会输出成对象。需要连续索引时用array_values包一层。

SORT_REGULAR的松散比较。SORT_REGULAR用的是PHP的松散比较规则,在PHP8之前,"1abc"==1会判为true,PHP8之后行为有变化。如果数组里有这类混合值,去重结果和预期可能不同。建议在去重前先规范数据类型。

多维数组不适用。array_unique只能处理一维数组,遇到子数组会报「Arraytostringcorsion」的提示,或者用SORT_REGULAR时按数组引用比较,结果不可预期。多维数组去重需要自己写递归或序列化后去重。

大数据量下的性能。array_unique内部会做排序,时间复杂度大约是O(nlogn)。数据量很大时如果只是想去重,用array_flip配合array_keys在某些场景下更快,因为哈希表查找是O(n)。不过array_flip只能处理字符串和整数,且会丢失键名信息。

七、本节课程知识要点

  • array_unique针对值去重,键名不参与重复判断

  • 重复时保留首次出现的元素,丢弃后续出现的

  • 结果数组保留原始键名,不重新索引

  • 返回新数组,不修改原数组

  • sort_flags决定比较规则,默认是SORT_STRING

  • 字符串"1"和整数1在默认规则下相等,字符串"01"和"1"不等

  • 需要连续索引时用array_values包一层

  • 多维数组去重需要额外处理

八、适用场景

这个函数适合以下场景:

  • 一维字符串数组去重

  • 关联数组按值去重,保留原始键名

  • 表单多选值去重

  • 标签、分类等简单列表去重

不适合的场景:

  • 多维数组去重,需要自己写递归逻辑

  • 需要保留所有重复项的场景

  • 数据量特别大且只需去重,可考虑array_flip方案

  • 需要按键名去重的场景,用array_unique不适用,得用其他方法

← PHP uksort函数详解:用自定义回调按数组键名排序 PHP array_unshift函数详解:数组头部插入元素与键名重建机制 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号