array_unique($array) 返回删除了重复值的数组。每个值第一次出现的元素会保留在原来的键下,后面的副本则被丢弃。
第一个结果保留了键 0, 1, 3:也就是每个值第一次出现的位置。如果你想要一个干净的列表,比如在 json_encode 之前,就用 array_values() 把调用包起来。
array_unique 怎样判断两个值相同
默认情况下,每个值都会先转换成字符串,再比较这些字符串。所以 1、"1" 和 1.0 被视为同一个值,第一个会被保留。第二个参数可以改变比较方式。
| 标志 | 两个值被视为重复的条件 |
|---|---|
SORT_STRING(默认) | (string) $a === (string) $b |
SORT_REGULAR | $a == $b |
SORT_NUMERIC | 作为数字时相等 |
使用默认方式时,"01" 会被保留,因为字符串 "01" 不等于字符串 "1"。使用 SORT_REGULAR 时它会被丢弃,因为 "01" == 1 为 true。宽松比较还会让布尔值 true 匹配任何非空值。对混合类型使用之前,先检查一下输出;比较运算符一页解释了这些规则。
不区分大小写地去重
array_unique 区分大小写:"PHP" 和 "php" 是不同的值。如果想把它们当作重复值,同时保留第一个值的原始写法,就在一个转成小写的副本上找出唯一的键,再从原数组中保留这些键。
array_map 生成一个键相同的小写副本,array_unique 保留第一次出现的那些键,array_intersect_key 再从原数组中挑出这些键。对于带重音符号的文字或中文、日文等文本,请用 mb_strtolower 代替 strtolower。
对多维数组使用 array_unique
不传标志时,array_unique 会把每一行都转换成字符串 "Array",于是所有行看起来都一样,只有第一行被保留,而且每一行都会产生一条“Array to string conversion”警告。传入 SORT_REGULAR 就会比较整行。如果要让某个字段的每个值只保留一行,用 array_column 配合 null 和索引键会更简单。
第二种方法会为每个邮箱保留最后一行,因为后面的每一行都会覆盖同一个键下前面的行。array_column 一页详细讲解了索引键。
找出并统计重复的值
array_count_values() 返回每个值出现的次数。从中筛选出次数大于一的,就得到了重复的值。
最后的检查是一个常用的单行写法,用来判断数组中到底有没有重复值。
大数组的更快去重方法
array_unique 在比较之前会把每个值都转换成字符串,对几千个值来说这没有问题。但对于一个很大的整数或字符串列表,把数组翻转会更快:值变成了键,而键本身就是唯一的。
每次运行的耗时都会不同,但翻转的方法通常要快好几倍。它只适用于能作为数组键的值(整数和字符串),而且像 "5" 这样的数字字符串返回时会变成整数。
常见问题
array_unique 会保留键吗?
会。它把每个值第一次出现的元素保留在原来的键下,丢弃后面出现的,所以键可能会有空缺。用 array_values(array_unique($arr)) 把它们从 0 开始重新编号。
怎样对多维数组使用 array_unique?
传入 SORT_REGULAR,这样会比较整行:array_unique($rows, SORT_REGULAR)。如果要让某个字段的每个值只保留一行,比如每个邮箱一行,就按这个字段给行建立索引:array_column($rows, null, 'email') 会为每个邮箱保留最后一行。
怎样不区分大小写地删除重复值?
在一个转成小写的副本上找出唯一的键,再从原数组中保留这些键:array_intersect_key($arr, array_unique(array_map('strtolower', $arr)))。对于 ASCII 以外的文本,请使用 mb_strtolower。
怎样找出 PHP 数组中哪些值重复了?
先用 array_count_values($arr) 统计次数,再保留次数大于一的:array_keys(array_filter(array_count_values($arr), fn($n) => $n > 1))。array_count_values 只适用于字符串和整数。