Question
I have a Ruby array that contains duplicate elements:
copy_array = [1, 2, 2, 1, 4, 4, 5, 6, 7, 8, 5, 6]
How can I remove the duplicate values from this array while keeping only unique elements, without writing explicit for loops or manual iteration?
Short Answer
By the end of this page, you will understand how Ruby removes duplicates from arrays using built-in methods such as uniq and uniq!. You will also learn when to use the non-destructive versus destructive version, what order Ruby keeps, and how this pattern is used in real code.
Concept
In Ruby, arrays often contain repeated values. Removing duplicates is a common task called deduplication.
Ruby provides built-in methods so you do not need to write your own loop for this. The most common method is:
array.uniq
This returns a new array containing each value only once.
For example:
[1, 2, 2, 1, 4].uniq
# => [1, 2, 4]
Ruby keeps the first occurrence of each value and removes later repeats.
This matters because deduplication appears often in real programs:
- cleaning user input
- removing repeated IDs from database results
- processing tags or categories
- preparing data before counting or grouping
- avoiding duplicate work in scripts or APIs
Ruby's built-in methods are preferred because they are short, readable, and optimized compared with manually writing loops.
Mental Model
Think of uniq like a guest list at an event.
- The first time a person's name appears, they are added to the list.
- If the same name appears again later, it is ignored.
- The final list contains each guest only once, in the order they first appeared.
So this:
[1, 2, 2, 1, 4, 4]
becomes:
[1, 2, 4]
because Ruby keeps the first 1, first 2, and first 4, then skips the repeats.
Syntax and Examples
The main Ruby methods for removing duplicates from arrays are:
array.uniq # returns a new deduplicated array
array.uniq! # modifies the original array in place
Basic example
copy_array = [1, 2, 2, 1, 4, 4, 5, 6, 7, 8, 5, 6]
unique_values = copy_array.uniq
puts unique_values.inspect
# => [1, 2, 4, 5, 6, 7, 8]
copy_array stays unchanged because uniq returns a new array.
In-place example
copy_array = [1, 2, 2, 1, 4, 4, 5, 6, 7, 8, 5, 6]
copy_array.uniq!
puts copy_array.inspect
# => [1, 2, 4, 5, 6, 7, 8]
Here, the original array is modified.
Strings example
names = ["Ana", "Ben", "Ana", "Chris", "Ben"]
puts names.uniq.inspect
# => ["Ana", "Ben", "Chris"]
Important behavior: order is preserved
numbers = [3, 1, 3, 2, 1]
puts numbers.uniq.inspect
# => [3, 1, 2]
Ruby does not sort the array here. It keeps the first appearance order.
Step by Step Execution
Consider this code:
copy_array = [1, 2, 2, 1, 4, 4, 5]
result = copy_array.uniq
Step by step, Ruby effectively builds the result like this:
- Start with an empty result.
- Read
1-> not seen before, keep it.- result:
[1]
- result:
- Read
2-> not seen before, keep it.- result:
[1, 2]
- result:
- Read
2again -> already seen, skip it.- result:
[1, 2]
- result:
- Read
1again -> already seen, skip it.- result:
[1, 2]
- result:
- Read
4-> not seen before, keep it.- result:
[1, 2, 4]
- result:
- Read
4again -> already seen, skip it.- result:
[1, 2, 4]
- result:
- Read
5-> not seen before, keep it.- result:
[1, 2, 4, 5]
- result:
Final result:
[1, 2, 4, 5]
Original array:
[1, 2, 2, 1, 4, 4, 5]
If you used uniq, the original stays the same.
If you used uniq!, the original would be changed.
Real World Use Cases
Removing duplicates from arrays is useful in many practical situations.
Cleaning form or API input
A user might submit repeated values:
tags = ["ruby", "api", "ruby", "backend"]
clean_tags = tags.uniq
# => ["ruby", "api", "backend"]
Preventing duplicate database IDs
user_ids = [12, 15, 12, 18, 15]
unique_user_ids = user_ids.uniq
# => [12, 15, 18]
Avoiding repeated work
If a job queue or script gets duplicate items, deduplication helps avoid processing the same item twice.
file_paths = ["a.txt", "b.txt", "a.txt"]
file_paths.uniq.each do |path|
puts "Processing #{path}"
end
Building filter lists
categories = ["books", "games", "books", "music"]
menu_items = categories.uniq
# => ["books", "games", "music"]
Real Codebase Usage
In real Ruby projects, uniq is often used as part of a data-cleaning pipeline.
Common pattern: sanitize then deduplicate
emails = ["a@example.com", "b@example.com", "a@example.com"]
clean_emails = emails.map(&:downcase).uniq
This normalizes values first, then removes duplicates.
Common pattern: deduplicate before querying
ids = params[:user_ids].uniq
users = User.where(id: ids)
This avoids unnecessary repeated IDs.
Common pattern: guard clauses with empty arrays
def fetch_users(ids)
ids = ids.uniq
return [] if ids.empty?
User.where(id: ids)
end
Common pattern: combine arrays, then deduplicate
all_roles = default_roles + custom_roles
all_roles = all_roles.uniq
Destructive updates when mutation is intended
config[:hosts].uniq!
Developers use uniq! only when changing the original array is safe and expected.
Common Mistakes
1. Confusing uniq with uniq!
uniq returns a new array.
uniq! changes the existing array.
numbers = [1, 1, 2]
numbers.uniq
puts numbers.inspect
# => [1, 1, 2]
Why? Because the result of uniq was not assigned.
Correct:
numbers = [1, 1, 2]
numbers = numbers.uniq
# or
numbers.uniq!
2. Expecting the result to be sorted
numbers = [3, 1, 3, 2, 1]
puts numbers.uniq.inspect
# => [3, 1, 2]
uniq removes duplicates, but it does not sort.
If you want both deduplication and sorting:
puts numbers.uniq.sort.inspect
# => [1, 2, 3]
3. Forgetting that uniq! can return nil
If no duplicates are removed, uniq! returns nil.
numbers = [1, 2, 3]
result = numbers.uniq!
puts result.inspect
# => nil
This can surprise beginners.
4. Using manual loops unnecessarily
Broken or overly verbose approach:
result = []
for item in copy_array
result << item unless result.include?(item)
end
This works, but Ruby already provides a clearer built-in solution:
result = copy_array.uniq
5. Assuming different-looking values are duplicates
values = [1, "1", 1]
puts values.uniq.inspect
# => [1, "1"]
1 and "1" are different values and are not treated as duplicates.
Comparisons
| Approach | Changes original array? | Return value | Best use |
|---|---|---|---|
array.uniq | No | New array with duplicates removed | When you want to keep the original |
array.uniq! | Yes | Modified array, or nil if unchanged | When you intentionally want in-place modification |
Manual loop + include? | Usually no | Depends on implementation | Rarely needed for basic deduplication |
array.uniq.sort | No | New unique and sorted array | When you need uniqueness and order sorted |
uniq vs uniq!
arr = [1, 1, 2]
arr.uniq # => [1, 2]
arr # => [1, 1, 2]
arr.uniq! # => [1, 2]
arr # => [1, 2]
uniq vs sort.uniq
arr = [3, 1, 3, 2, 1]
arr.uniq # => [3, 1, 2]
arr.sort.uniq # => [1, 2, 3]
Use uniq if you want to preserve first-seen order.
Use sort.uniq if you want sorted output.
Cheat Sheet
# Remove duplicates and return a new array
array.uniq
# Remove duplicates by modifying the original array
array.uniq!
Key rules
uniqdoes not modify the original array.uniq!does modify the original array.uniqpreserves the order of first appearance.uniqdoes not sort values.uniq!returnsnilif no changes were made.
Examples
[1, 2, 2, 1].uniq
# => [1, 2]
arr = [1, 1, 2]
arr.uniq!
# arr is now [1, 2]
Common combinations
array.uniq.sort # unique then sorted
array.map(&:downcase).uniq
array.compact.uniq # remove nil values, then duplicates
Watch out for
[1, "1", 1].uniq
# => [1, "1"]
Different types are not duplicates.
FAQ
How do I remove duplicates from an array in Ruby?
Use uniq:
array.uniq
It returns a new array with duplicates removed.
What is the difference between uniq and uniq! in Ruby?
uniq returns a new array. uniq! changes the original array in place.
Does Ruby uniq keep the original order?
Yes. Ruby keeps the first occurrence of each element and preserves that order.
Does uniq remove all repeated values from an array of strings?
Yes, as long as the strings are equal.
["a", "b", "a"].uniq
# => ["a", "b"]
Why does uniq! return nil sometimes?
If the array already has no duplicates, uniq! makes no change and returns nil.
Can I remove duplicates without writing a loop in Ruby?
Yes. uniq and uniq! are built-in methods, so you do not need to write an explicit loop yourself.
Can I sort the array after removing duplicates?
Yes:
array.uniq.sort
Mini Project
Description
Build a small Ruby script that cleans a list of repeated email addresses before sending a newsletter. This demonstrates how deduplication prevents sending the same message multiple times.
Goal
Create a Ruby program that removes duplicate email addresses and prints the cleaned list.
Requirements
- Store a list of email addresses in an array with some duplicates.
- Remove duplicate email addresses using a built-in Ruby method.
- Keep the original order of the first occurrence.
- Print both the original array and the cleaned array.
Keep learning
Related questions
Add a Default Value to an Existing Column in a Rails Migration
Learn how to add or change a default value on an existing database column using Rails Active Record migrations safely.
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.