Array#uniq
Array · Updated April 1, 2026 · Array Methods What does uniq do?
uniq returns a new array with duplicate elements removed. By default, elements are compared using == — if two elements are equal, only the first occurrence is kept and subsequent duplicates are discarded.
Array#uniq is defined directly on the Array class but behaves identically to Enumerable#uniq — Array includes Enumerable and overrides uniq with an optimised implementation.
Basic Usage
Removing duplicate numbers
[1, 2, 2, 3, 1, 4, 3, 5].uniq
# => [1, 2, 3, 4, 5]
The first occurrence of each value is preserved. 1 appears at index 0, 2 at index 1, 3 at index 3, etc.
With strings
names = ["Alice", "Bob", "Alice", "Charlie", "Bob", "Diana"]
names.uniq
# => ["Alice", "Bob", "Charlie", "Diana"]
Empty and single-element arrays
[].uniq
# => []
[42].uniq
# => [42]
With a Block
Pass a block to determine uniqueness based on the block’s return value instead of the elements themselves:
words = ["apple", "apricot", "banana", "blueberry", "cherry"]
words.uniq { |word| word[0] }
# => ["apple", "banana", "cherry"]
"apple"[0] and "apricot"[0] both return "a", so only the first "a"-word survives. The block result drives uniqueness — elements producing the same block value are considered duplicates.
Practical example: unique by attribute
users = [
{ name: "Alice", role: "admin" },
{ name: "Bob", role: "member" },
{ name: "Charlie", role: "admin" },
{ name: "Diana", role: "member" }
]
users.uniq { |u| u[:role] }
# => [{:name=>"Alice", :role=>"admin"},
# {:name=>"Bob", :role=>"member"}]
One record per role — useful when you need a representative from each category.
Order Preservation
uniq preserves the original order of elements. The first occurrence of each unique element is kept in its original position:
[3, 1, 4, 1, 5, 9, 2, 6].uniq
# => [3, 1, 4, 5, 9, 2, 6]
This matters when the sequence of elements carries meaning — unlike sorting or other transformations that reorder results.
The Bang Variant: uniq!
The uniq! method mutates the original array in place. If duplicates were removed, it returns the same array. If no duplicates existed, it returns nil.
numbers = [1, 2, 2, 3, 1, 4, 3, 5]
result = numbers.uniq!
numbers # => [1, 2, 3, 4, 5]
result # => [1, 2, 3, 4, 5]
result.equal?(numbers) # => true (same object)
When uniq! returns nil
If the array already contains only unique elements, uniq! returns nil and leaves the array unchanged:
numbers = [1, 2, 3]
result = numbers.uniq!
result # => nil
numbers # => [1, 2, 3]
Comparing uniq vs uniq!
original = [1, 2, 2, 3, 1]
# uniq returns a new array, original unchanged
deduped = original.uniq
original # => [1, 2, 2, 3, 1]
deduped # => [1, 2, 3]
# uniq! modifies the original
original.uniq!
original # => [1, 2, 3]
Difference from & (Set Intersection)
Ruby has two ways to work with unique elements. uniq removes duplicates from a single array. & finds elements present in both of two arrays:
a = [1, 2, 2, 3, 4]
b = [2, 3, 3, 5]
# uniq removes duplicates from ONE array
a.uniq
# => [1, 2, 3, 4]
# & finds elements present in BOTH arrays
a & b
# => [2, 3]
uniq operates on one array and deduplicates it. & requires two arrays and returns their intersection.
When to use each
- Use
uniqwhen you want to remove duplicates from one list - Use
&when you want common elements between two lists
# Deduplicate one list
["cat", "dog", "cat", "mouse"].uniq
# => ["cat", "dog", "mouse"]
# Find overlapping tags
user_tags = ["ruby", "rails", "postgres"]
post_tags = ["ruby", "python", "postgres"]
user_tags & post_tags
# => ["ruby", "postgres"]
Performance Considerations
uniq iterates through the array once and uses a hash internally to track seen elements. This gives it O(n) time complexity, where n is the array size.
require "benchmark"
array = (1..1000).to_a + (1..500).to_a # 1500 elements, 500 duplicates
Benchmark.measure do
array.uniq
end.real # => ~0.0002s
The uniq! variant avoids allocating a new array, which saves memory for large arrays. The iteration cost is the same — the performance difference is solely in allocation.
For block-based uniqueness, the hash stores the block result as the key rather than the element itself:
data = [1, 2, 3, 4, 5]
data.uniq { |n| n.even? ? "even" : "odd" }
# => [1, 2]
This is still O(n) — hashing the block result is constant time.
Edge Cases
nil values
nil is treated as a regular value and participates in uniqueness checking:
[1, nil, 2, nil, 3].uniq
# => [1, nil, 2, 3]
One nil is kept alongside one occurrence of each unique non-nil value.
With a block returning nil
If the block returns nil for multiple elements, those elements are considered duplicates:
data = [1, 2, 3, 4]
data.uniq { |n| n.even? ? "even" : nil }
# => [1, 2]
Odd numbers (1, 3) both produce nil from the block, so only the first odd number survives.
Hash elements
Hashes use hash and eql? for uniqueness, not just ==:
[{a: 1}.hash] # not directly comparable to [{a: 1}]
Ruby’s Hash class handles deduplication internally, but when using uniq on an array of hashes, two hashes with identical contents are considered equal.
Practical Examples
Removing duplicate names
attendees = ["Alice", "Bob", "Charlie", "Alice", "Diana", "Bob"]
attendees.uniq
# => ["Alice", "Bob", "Charlie", "Diana"]
Finding unique values by attribute
products = [
{ name: "Laptop", category: "electronics" },
{ name: "Mouse", category: "electronics" },
{ name: "Carrot", category: "food" },
{ name: "Apple", category: "food" }
]
products.uniq { |p| p[:category] }
# => [{:name=>"Laptop", :category=>"electronics"},
# {:name=>"Carrot", :category=>"food"}]
Cleaning extracted URLs
urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page1",
"https://example.com/page3"
]
urls.uniq
# => ["https://example.com/page1",
# "https://example.com/page2",
# "https://example.com/page3"]
Chaining with other array methods
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 5]
numbers.uniq.select(&:odd?) # => [1, 3, 5]
numbers.uniq.map { |n| n * 10 } # => [10, 20, 30, 40, 50]
numbers.uniq.reject { |n| n > 3 } # => [1, 2, 3]
See Also
- /reference/array-methods/array-reject/ — Returns a new array with elements for which the block evaluates to false
- /reference/array-methods/array-map/ — Transforms each element in the array
- /reference/enumerable/enumerable-uniq/ — The Enumerable version of uniq with the same behaviour