RubyGuides
Share this post!

Fast Lookup & Unique Elements With The Ruby Set Class

A set is a class that can hold items in a similar way that an array does…

…but with some special attributes.

With the main benefit being this:

All the items in a set are guaranteed to be unique.

In this Ruby tutorial you’ll learn:

  • How & when to use a set for maximum benefit
  • The difference between sets & arrays
  • A list of useful set methods

Let’s get started!

Ruby Set Examples

A set is a Ruby class that helps you create a list of unique items.

Here’s an example of how this is useful:

Let’s say you are going over a big list of products.

But there are duplicated entries in this list & you only want unique products.

You could put them in a set, and the set will make sure your product list is always unique without any extra work.

Here’s how to do that:

require 'set'

products = Set.new

products << 1
products << 1
products << 2

products
# Set: {1, 2}

Another benefit is that searching this list is going to be very fast:

products.include?(1)

# true

This is so fast because the search is made in constant time.

Set vs Array - Understanding The Difference

Now you may be wondering...

What's the difference between a set & an array?

A set has no direct access to elements:

products[0]

# undefined method `[]'

That's the main difference.

But a set can be converted into an array any time you need:

products.to_a

# [1, 2]

The whole point of using a set is to use its two special attributes:

  • Fast lookup times (with include?)
  • Unique values

If you need these then a set will give you a good performance boost, and you won't have to be calling uniq on your array every time you want unique elements.

Set vs Array Benchmark

Here's a benchmark to show you the performance difference between array & set include? methods.

# Ruby 2.5.0

set   include: 8381985.2 i/s
array include: 703305.5  i/s - 11.92x  slower

The reason for this difference is that an array has to check every single element...

...if you have a 1 million element array it's going to be checking 1 million elements every time you call include?.

A set doesn't have to do that.

Set Methods

One of the useful set methods is the union operator:

products | (1..10)

# Set: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

This works with any Enumerable object, like arrays, ranges & hashes.

Here's the difference operator:

products - (3..4)

# Set: {1, 2, 5, 6, 7, 8, 9, 10}

And here's the set intersection operator:

Set.new(1..3) & Set.new(2..5)

# Set: {2, 3}

This gives you the elements common in both sets.

These 3 operators (union, difference & intersection) can also be used with arrays.

Superset & Subset

A superset is a set that contains all the elements of another set.

You can check if one set is a superset of another.

Like this:

Set.new(10..40) >= Set.new(20..30)

The range 10..40 contains 20..30 within it.

A subset is a set that is made from parts of another set:

Set.new(25..27) <= Set.new(20..30)

How to Use Sorted Sets

If you want a set that always stays sorted you can use the SortedSet class.

There are some requirements to using this class:

  1. The objects you are adding to the set must implement the <=> method.
  2. The objects must be comparable to each other (comparing integer to integer, or string to string)

Here's an example:

sorted_numbers = SortedSet.new

sorted_numbers << 5
sorted_numbers << 2
sorted_numbers << 1

sorted_numbers
# SortedSet: {1, 2, 5}

Sets Video Tutorial

Summary

You learned how to use sets in Ruby for better performance & easier coding. You also learned about the differences between arrays & sets.

Please share this article if you found it useful so more people can find it 🙂

Thanks for reading!

Leave a Comment: