LaunchKit
All quizzes
Ruby 0 views

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

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:

  1. Uniqueness: sets test membership with eql?/hash, so :ruby can only be present once.
  2. Ordering: SortedSet sorts elements with <=>, not by insertion order. Symbol implements <=> (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.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.