SortedSet keeps values unique and ordered
Question
What is the return value of the following Ruby code?
require 'set'
tags = SortedSet.new
tags << :ruby
tags << :algol
tags << :lua
tags << :ruby
tags.to_a # => ???
The correct answer is
-
[:ruby, :algol, :lua, :ruby] -
It raises
DuplicatesError -
[:ruby, :algol, :lua] -
[:algol, :lua, :ruby]Correct
Explanation
TL;DR
A SortedSet is a Set that keeps its elements in ascending order. Like every set it ignores duplicates, so the second << :ruby is a no-op, and to_a returns the three distinct symbols sorted by <=>: [:algol, :lua, :ruby]. Note that this snippet needs Ruby 2.7 or earlier, or the sorted_set gem: since Ruby 3.0, SortedSet is no longer part of the set standard library.
Step by step
On Ruby 2.7 (or any Ruby with the sorted_set gem installed):
require 'set'
tags = SortedSet.new
tags << :ruby # #<SortedSet: {:ruby}>
tags << :algol # #<SortedSet: {:algol, :ruby}>
tags << :lua # #<SortedSet: {:algol, :lua, :ruby}>
tags << :ruby # #<SortedSet: {:algol, :lua, :ruby}> (duplicate, ignored)
tags.to_a # => [:algol, :lua, :ruby]
Two properties combine here:
- Uniqueness: sets test membership with
eql?/hash, so:rubycan only be present once. - Ordering:
SortedSetsorts elements with<=>, not by insertion order.Symbolimplements<=>(it compares the symbols' string forms), so:algol < :lua < :ruby.
Every element must be comparable with every other; pushing, say, an Integer next to the Symbols raises ArgumentError as soon as the set tries to order them (the exact message varies by implementation).
Version notes
SortedSet shipped inside the set standard library up to Ruby 2.7. Ruby 3.0 extracted it into the standalone sorted_set gem (which uses an efficient red-black tree via rbtree). What require 'set' gives you afterwards depends on the version:
On Ruby 3.0 through 3.4, the library leaves behind a stub constant that fails on use:
require 'set'
begin
SortedSet.new
rescue RuntimeError => e
e.message # => "The `SortedSet` class has been extracted from the `set` library. You must use the `sorted_set` gem or other alternatives."
end
On Ruby 4.0, even the stub is gone, so the reference itself raises NameError:
require 'set'
defined?(SortedSet) # => nil
To run the quiz snippet on a modern Ruby, add gem "sorted_set" to your Gemfile and require 'sorted_set'.
Without the gem
A plain Set plus sort covers most use cases: keep uniqueness at insertion time and sort when you read:
require 'set'
tags = Set.new
tags << :ruby << :algol << :lua << :ruby
tags.to_a # => [:ruby, :algol, :lua] (insertion order)
tags.sort # => [:algol, :lua, :ruby]
The difference is complexity: SortedSet maintains order on every insert, while Set#sort pays the sorting cost on every read. For a large, frequently read collection, the gem's red-black tree wins.
Share this quiz
Comments
No comments yet. Be the first.