Array#uniq
The .uniq method removes duplicate elements from an array, keeping only the first occurrence of each unique value. The .uniq! variant modifies the array in place.
numbers = [1, 1, 2, 2, 3, 3, 4, 4]
numbers.uniq
# => [1, 2, 3, 4]
# uniq! modifies in place
arr = [1, 1, 2, 2, 3]
arr.uniq!
arr # => [1, 2, 3]
Syntax
array.uniq
array.uniq { |element| block }
array.uniq!
array.uniq! { |element| block }
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| block | Block | Optional | If provided, determines uniqueness based on the block’s return value |
What .uniq Returns
.uniq returns a new array containing unique elements. The original array remains unchanged.
original = [1, 2, 2, 3, 3, 3]
unique = original.uniq
original # => [1, 2, 2, 3, 3, 3] (unchanged)
unique # => [1, 2, 3] (new array)
.uniq! returns self if duplicates were removed, or nil if the array already had no duplicates:
arr = [1, 2, 3]
result = arr.uniq!
# => nil (no changes made)
arr = [1, 1, 2]
result = arr.uniq!
# => [1, 2] (returns self)
Using a Block
Pass a block to determine uniqueness based on a computed value:
# Get unique lengths
words = ["cat", "dog", "horse", "mouse", "cow"]
words.uniq { |word| word.length }
# => ["cat", "horse", "mouse"]
# First "cat" (len 3), then "horse" (len 5), then "mouse" (len 5 - duplicate!)
# Result: ["cat", "horse", "mouse"]
This is useful when you want uniqueness based on a specific attribute rather than the element itself.
Common Use Cases
Removing Duplicates from User Input
# Form submissions often have duplicate values
emails = ["user@example.com", "admin@example.com", "user@example.com"]
emails.uniq
# => ["user@example.com", "admin@example.com"]
Processing Database Results
# Database queries might return duplicate records
user_ids = [1, 2, 1, 3, 2, 1]
user_ids.uniq
# => [1, 2, 3]
With Chaining
# Chain with other methods
[1, 1, 2, 2, 3, 3].select(&:odd?).uniq
# => [1, 3]
# Get unique values and sort
[3, 1, 2, 3, 1, 2].uniq.sort
# => [1, 2, 3]
Gotchas
Understanding First Occurrence Retention
.uniq always keeps the first occurrence, regardless of position:
# The second "cat" is removed, even though duplicates exist elsewhere
["cat", "dog", "cat", "bird", "cat"].uniq
# => ["cat", "dog", "bird"]
Block Returns nil
If the block returns nil, elements are compared by their nil status:
[1, 2, nil, nil, 3].uniq { |n| n&.even? }
# => [1, nil, 3]
# 1 -> even? returns false
# 2 -> even? returns true (kept)
# nil -> even? returns nil (different from false, kept)
# nil -> even? returns nil (same as previous nil, removed)
# 3 -> even? returns false (different from true, kept)
Hash Keys and uniq
Ruby hashes don’t allow duplicate keys, so converting through a hash can also remove duplicates (though order may vary in older Ruby):
# Alternative approach for uniqueness
[1, 2, 1, 3, 2].each_with_object({}) { |n, h| h[n] = true }.keys
# => [1, 2, 3]
# But prefer uniq for clarity and guaranteed order