array_unique($array) returns the array with duplicate values removed. The first occurrence of each value stays, under its original key, and the later copies are dropped.
The first result keeps the keys 0, 1, 3: the positions where each value first appeared. Wrap the call in array_values() when you want a clean list, for example before json_encode.
How array_unique decides two values are the same
By default each value is converted to a string and the strings are compared. So 1, "1" and 1.0 count as the same value, and the first one wins. The second argument changes the comparison.
| Flag | Two values are duplicates when |
|---|---|
SORT_STRING (default) | (string) $a === (string) $b |
SORT_REGULAR | $a == $b |
SORT_NUMERIC | they are equal as numbers |
With the default, "01" survives because the string "01" is not the string "1". With SORT_REGULAR it is dropped, because "01" == 1 is true. Loose comparison also lets the boolean true match any non-empty value. Check the output before you rely on it with mixed types; the comparison operators page explains the rules.
Remove duplicates ignoring case
array_unique is case-sensitive: "PHP" and "php" are different. To treat them as duplicates but keep the original spelling of the first one, find the unique keys on a lowercased copy and keep those keys from the original.
array_map builds a lowercased copy with the same keys, array_unique keeps the keys of the first occurrences, and array_intersect_key picks those keys out of the original array. For accented or Japanese text, use mb_strtolower in place of strtolower.
array_unique on a multidimensional array
Without a flag, array_unique converts every row to the string "Array", so all rows look identical and only the first survives, with an "Array to string conversion" warning for every row. Pass SORT_REGULAR to compare whole rows. To keep one row per value of a single field, array_column with null and an index key is simpler.
The second approach keeps the last row for each email because each later row overwrites the earlier one under the same key. The array_column page explains the index key in detail.
Find and count duplicate values
array_count_values() returns how many times each value appears. Filter that for counts above one and you have the duplicates.
The last check is a common one-liner to test whether an array has any duplicates at all.
Faster unique values for large arrays
array_unique converts every value to a string before comparing, which is fine for thousands of values. For a large list of integers or strings, flipping the array is faster: values become keys, and keys are unique by definition.
The timings change from run to run, but the flip version is usually several times faster. It only works for values that can be array keys (integers and strings), and numeric strings such as "5" come back as integers.
Frequently Asked Questions
Does array_unique keep the keys?
Yes. It keeps the first occurrence of each value under its original key and drops the later ones, so the keys can have gaps. Use array_values(array_unique($arr)) to renumber them from 0.
How do I use array_unique on a multidimensional array?
Pass SORT_REGULAR so whole rows are compared: array_unique($rows, SORT_REGULAR). To keep one row per value of a field, such as one row per email, index the rows by that field: array_column($rows, null, 'email') keeps the last row for each email.
How do I remove duplicates ignoring upper and lower case?
Find the unique keys on a lowercased copy and keep those keys from the original: array_intersect_key($arr, array_unique(array_map('strtolower', $arr))). Use mb_strtolower for text outside ASCII.
How do I find which values are duplicated in a PHP array?
Count them with array_count_values($arr), then keep the counts above one: array_keys(array_filter(array_count_values($arr), fn($n) => $n > 1)). array_count_values works on strings and integers only.