Sets

Reviewed & published by Brayan K

A Set is an unordered collection that stores only unique elements and offers fast membership checks, making it the right tool whenever duplicates must be rejected or "have I seen this?" must be answered quickly.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

You'll build sets, add elements, test membership, and combine them with set algebra — union |, intersection &, difference - — then dedupe arrays the efficient way.

What You'll Learn in This Lesson

1️⃣ Creating Sets & Membership

After require 'set', build one with Set.new(array) — duplicates are dropped automatically. Add elements with add or its alias <<, and test membership with include?, which is far faster than scanning an array.

# A Set is an unordered collection of UNIQUE elements
require 'set'
s = Set.new([1, 2, 2, 3, 3, 3])   # duplicates vanish
p s                                # #<Set: {1, 2, 3}>
puts s.size                        # 3

s.add(4)        # add an element
s << 5          # << is an alias for add
s.add(1)        # already present -> no change
p s.to_a        # [1, 2, 3, 4, 5]

puts s.include?(3)   # true (membership test is FAST)
puts s.include?(9)   # false

2️⃣ Set Algebra

Sets support the operators from math class: | for union, & for intersection, - for difference, and ^ for symmetric difference. Each returns a new set, so the originals are untouched.

# Set algebra: union, intersection, difference
require 'set'
a = Set[1, 2, 3, 4]      # Set[...] literal shortcut
b = Set[3, 4, 5, 6]

p (a | b)     # union: everything in either           {1,2,3,4,5,6}
p (a & b)     # intersection: only in both            {3,4}
p (a - b)     # difference: in a but not b            {1,2}
p (a ^ b)     # symmetric difference: in exactly one  {1,2,5,6}

3️⃣ Subsets & Deduping

subset? and superset? answer containment questions, and converting an array with to_set deduplicates it. When you only need a one-off dedup back as an array, Array#uniq is fine; a Set wins when you'll repeatedly check membership.

# Subset / superset, and deduping an array
require 'set'
small = Set[1, 2]
big   = Set[1, 2, 3, 4]
puts small.subset?(big)      # true  (every element of small is in big)
puts big.superset?(small)    # true
puts small.subset?(Set[1, 9])# false

# Deduping an array while checking membership efficiently
emails = ["a@x.com", "b@x.com", "a@x.com", "c@x.com", "b@x.com"]
unique = emails.to_set        # Array -> Set
p unique.to_a                 # order preserved as first-seen
puts "Unique addresses: #{unique.size}"

# Array#uniq does the same for simple dedup, but a Set shines for
# repeated include? checks where Array would be O(n) each time.
p emails.uniq

Your turn. Fill in each ___ blank with the right operator, then run it.

# 🎯 YOUR TURN — fill in the blanks, then run with: ruby teams.rb

require 'set'
team_a = Set["Ann", "Bo", "Cy"]
team_b = Set["Bo", "Di", "Cy"]

both   = team_a ___ team_b      # 👉 intersection: people on BOTH teams
either = team_a ___ team_b      # 👉 union: everyone across both teams
puts "On both teams: #{both.to_a.sort.join(', ')}"
puts "Total people:  #{either.size}"

# ✅ Expected output:
#    On both teams: Bo, Cy
#    Total people:  4

Mini-Challenge: Find the Repeats

Use two sets — one for words you've seen, one for duplicates — to find which words appear more than once. Run with ruby repeats.rb.

# 🎯 MINI-CHALLENGE: find the repeated words in a sentence.
# Save as repeats.rb and run with: ruby repeats.rb
#
# text = "the quick brown fox the lazy dog the fox"
# 1. Split into words.
# 2. Keep a "seen" Set and a "duplicates" Set.
# 3. For each word: if it's already in seen, add it to duplicates;
#    otherwise add it to seen.
# 4. Print the number of distinct words and the sorted duplicates.
#
# ✅ Example output:
#    Distinct words: 6
#    Repeated words: fox, the

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Sets

GoalRuby Syntax
CreateSet.new([1,2]) , Set[1,2]
Adds.add(x) , s << x
Member?s.include?(x)
Union / intersectiona | b , a & b
Differencea - b , a ^ b
Dedup an arrayarray.to_set

🎉 Lesson Complete!

Practice quiz

What is the defining property of a Set?

  • It keeps insertion order
  • It allows duplicates
  • It stores only unique elements
  • It is always sorted

Answer: It stores only unique elements. A Set is an unordered collection that automatically rejects duplicate elements.

What does Set.new([1, 2, 2, 3, 3, 3]).size return?

  • 3
  • 6
  • 2
  • 1

Answer: 3. Duplicates vanish, leaving the unique elements {1, 2, 3}, so size is 3.

Which method tests membership in a Set?

  • has?
  • member
  • contains
  • include?

Answer: include?. include? checks membership and is effectively O(1) thanks to a hash internally.

Which operator computes the UNION of two sets?

  • &
  • |
  • -
  • ^

Answer: |. | is union — every element that is in either set.

Which operator computes the INTERSECTION of two sets?

  • &
  • |
  • -
  • +

Answer: &. & is intersection — only elements present in both sets.

Given a = Set[1,2,3,4] and b = Set[3,4,5,6], what is a - b?

  • {3, 4}
  • {5, 6}
  • {1, 2}
  • {1, 2, 5, 6}

Answer: {1, 2}. Difference a - b is elements in a but not b, which is {1, 2}.

What does the alias << do on a Set?

  • Removes an element
  • Adds an element (same as add)
  • Computes union
  • Sorts the set

Answer: Adds an element (same as add). << is an alias for add — it inserts one element.

Adding an element that is already present to a Set...

  • Raises an error
  • Duplicates it
  • Clears the set
  • Is a harmless no-op

Answer: Is a harmless no-op. Adding an existing element does nothing — the set never grows beyond its unique members.

Which method returns true when every element of small is also in big?

  • small.superset?(big)
  • small.subset?(big)
  • small.member?(big)
  • small.union?(big)

Answer: small.subset?(big). subset? is true when every element of the receiver is contained in the argument set.

What is the fastest way to dedupe an array and keep doing membership checks?

  • Repeated Array#include?
  • Sort it first
  • Convert it to a Set with to_set
  • Use a nested loop

Answer: Convert it to a Set with to_set. to_set gives O(1) include? checks, far faster than scanning an array repeatedly.

Continue this course

Frequently asked questions

How is a Set different from an Array?

An Array is an ordered list that allows duplicates and remembers insertion order; a Set is an unordered collection that automatically rejects duplicates. The biggest practical difference is membership testing: Array#include? scans every element (O(n)), while Set#include? uses a hash internally and is effectively O(1). So if you're repeatedly asking 'have I seen this before?', a Set is dramatically faster. Use an Array when order or duplicates matter, and a Set when you need uniqueness and quick lookups.

Do I need to require 'set'?

On older Rubies, yes — Set lived in the standard library and you had to add require 'set' before using it. As of Ruby 3.2 the Set class is autoloaded, so it often works without the require. For maximum compatibility and to make your intent explicit, it's still good practice to write require 'set' at the top of any file that uses sets. The convenient Array#to_set helper, in particular, is defined when the set library is loaded.

What do the operators |, &, -, and ^ do on sets?

They implement classic set algebra. | is union (every element that's in either set), & is intersection (only elements in both), - is difference (elements in the left set but not the right), and ^ is symmetric difference (elements in exactly one of the two sets). Each returns a brand-new Set and leaves the originals unchanged, so you can chain them freely — for example (a | b) - c. These read almost exactly like the math, which makes set-based logic very clear.

When should I just use Array#uniq instead of a Set?

For a one-shot 'remove duplicates from this list' where you want the result back as an ordered Array, Array#uniq is the simplest tool and keeps first-seen order. Reach for a Set when uniqueness is an ongoing invariant — you're adding items over time and want duplicates rejected automatically — or when you'll perform many include? checks, intersections, or unions. In short: uniq for a quick cleanup, Set when set-ness is core to your algorithm.