class Set

Practical examples and pitfalls for Set

Set examples: compare membership without keeping duplicates

Practical notes by Ruby-Doc.org

Ask which names were added or removed

A deployment report receives the previous list of active features and the current list. If duplicate names have no meaning, sets make the comparison direct. Difference finds names present on only one chosen side; intersection finds the names shared by both.

Example 1
require "set"
before = Set.new(%w[search export export])
after = Set.new(%w[search audit])
p (after - before).to_a.sort
p (before - after).to_a.sort
p (before & after).to_a.sort
Expected output
["audit"]
["export"]
["search"]

The results are sorted only for predictable display. Treat membership as the important property of the set. If the application needs a meaningful display order, define and apply that ordering when producing the report rather than deriving it from how the inputs happened to arrive.

Decide what counts as the same member

A value that looks like another value is not necessarily the same set member. Sets use equality rules based on eql? and hash. The example keeps an integer, a float and a string as distinct values, while repeated copies of the same integer do not increase the size.

Example 2
require "set"
values = Set.new([1, 1, 1.0, "1"])
p values.size
p values.include?(1)
p values.include?("01")
Expected output
3
true
false

For a tag editor, decide whether case differences and surrounding spaces should be significant. If they should not, normalize those strings before adding them to the set. A set removes duplicates according to its equality rules; it does not infer the naming rules of your application.

Keep members stable while they are stored

Custom objects used as members need compatible implementations of eql? and hash. Changing the state on which their membership identity depends while they are in the set can make later lookups surprising. Prefer values whose identity remains stable for the lifetime of the collection.

Test empty inputs and identical inputs in addition to a mixed change. They should produce an empty added or removed result where appropriate. If duplicates themselves are something the report must detect, inspect or count the original sequence before converting it into a set and losing that information.

API reference: Set API reference

Related: Array · Hash

The Set class implements a collection of unordered values with no duplicates. It is a hybrid of Array’s intuitive inter-operation facilities and Hash’s fast lookup.

Set is easy to use with Enumerable objects (implementing each). Most of the initializer methods and binary operators accept generic Enumerable objects besides sets and arrays. An Enumerable object can be converted to Set using the to_set method.

Set uses a data structure similar to Hash for storage, except that it only has keys and no values.

Comparison

The comparison operators <, >, <=, and >= are implemented as shorthand for the {proper_,}{subset?,superset?} methods. The <=> operator reflects this order, or returns nil for sets that both have distinct elements ({x, y} vs. {x, z} for example).

Example

s1 = Set[1, 2]                        #=> Set[1, 2]
s2 = [1, 2].to_set                    #=> Set[1, 2]
s1 == s2                              #=> true
s1.add("foo")                         #=> Set[1, 2, "foo"]
s1.merge([2, 6])                      #=> Set[1, 2, "foo", 6]
s1.subset?(s2)                        #=> false
s2.subset?(s1)                        #=> true

Contact

Inheriting from Set

Before Ruby 4.0 (released December 2025), Set had a different, less efficient implementation. It was reimplemented in C, and the behavior of some of the core methods were adjusted.

To keep backward compatibility, when a class is inherited from Set, additional module Set::SubclassCompatible is included, which makes the inherited class behavior, as well as internal method names, closer to what it was before Ruby 4.0.

It can be easily seen, for example, in the inspect method behavior:

p Set[1, 2, 3]
# prints "Set[1, 2, 3]"

class MySet < Set
end
p MySet[1, 2, 3]
# prints "#<MySet: {1, 2, 3}>", like it was in Ruby 3.4

For new code, if backward compatibility is not necessary, it is recommended to instead inherit from Set::CoreSet, which avoids including the “compatibility” layer:

class MyCoreSet < Set::CoreSet
end
p MyCoreSet[1, 2, 3]
# prints "MyCoreSet[1, 2, 3]"

Set’s methods

First, what’s elsewhere. Class Set:

In particular, class Set does not have many methods of its own for fetching or for iterating. Instead, it relies on those in Enumerable.

Here, class Set provides methods that are useful for:

Methods for Creating a Set

Methods for Set Operations

Methods for Comparing

Methods for Querying

Methods for Assigning

Methods for Deleting

Methods for Converting

Methods for Iterating

Other Methods