123456789_123456789_123456789_123456789_123456789_

Class: Set

Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, ::Enumerable
Inherits: Object
Defined in: set.c,
set.c

Overview

An instance of class Set contains a collection of objects (elements), with no duplicates.

By default:

  • Set determines equality via Object#eql? and Object#hash, and assumes that these values do not change for a stored element. If these values do change, the set enters an unreliable state; see #reset.
  • A String instance added to a set is stored as a frozen copy of the string, unless it is already frozen.

Calling #compare_by_identity causes:

  • All following determinations of equality to use object identity instead of the methods mentioned above.
  • A String added to a set is stored "as is", whether or not frozen.

Set includes module ::Enumerable, and is easy to use with other enumerable objects. Many of its methods accept enumerable objects as arguments; any enumerable object may be converted to a set via #to_set.

Contact

Inheriting from Set

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

When compatibility with the older implementation is needed, a Set subclass should inherit directly from class Set; this automatically includes module Set::SubclassCompatible, which makes behaviors closer to those in the older implementation.

A difference may be seen as follows:

Set[[1, 2, 3]]       # => Set[[1, 2, 3]]
class MySet < Set; end
MySet[[1, 2, 3]]     # => #<MySet: {[1, 2, 3]}>  # Same as in Ruby 3.4.

When backward compatibility is not needed, a Set subclass should inherit from Set::CoreSet, which avoids including the compatibility layer:

class MyCoreSet < Set::CoreSet; end
MyCoreSet[[1, 2, 3]] # => MyCoreSet[[1, 2, 3]]

What's Here

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

  • .[]: Returns a new set populated with the given objects.
  • .new: Returns a new set based on the given object (if no block given), or on the return values from the called block (if a block given).

Methods for Set Operations

  • #& (aliased as #intersection): Returns a new set containing the intersection of self and the given enumerable.
  • #- (aliased as #difference): Returns a new set containing the difference of self and the given enumerable.
  • #^: Returns a new set containing the exclusive OR of self and the given enumerable.
  • #| (aliased as #union and #+): Returns a new set containing the union of self and the given enumerable.

Methods for Comparing

  • #<=>: Returns -1, 0, or 1 as self is less than, equal to, or greater than a given object.
  • #==: Returns whether self and a given enumerable are equal, as determined by Object#eql?.
  • #compare_by_identity?: Returns whether self considers only identity when comparing elements.
  • #proper_subset? (aliased as #<): Returns whether the given enumerable is a proper subset of self.
  • #proper_superset? (aliased as #>): Returns whether the given enumerable is a proper superset of self.
  • #subset? (aliased as #<=): Returns whether the given object is a subset of self.
  • #superset? (aliased as #>=): Returns whether the given enumerable is a superset of self.

Methods for Querying

  • #disjoint?: Returns whether no element of the given enumerable is present in self.
  • #empty?: Returns whether self contains no elements.
  • #include? (aliased as #member? and #===): Returns whether the given object is an element of self.
  • #intersect?: Returns whether self and the given enumerable have any elements in common.
  • #size (aliased as #length): Returns the number of elements in self.

Methods for Assigning

  • #add (aliased as #<<): Adds the given object to self; returns self.
  • #add?: Like #add, but returns nil if the given object is already in self.
  • #merge: Adds each element of each of the given enumerables to self; returns self.
  • #replace: Replaces the contents of self with the contents of the given enumerable; returns self.

Methods for Deleting

  • #clear: Removes all elements from self; returns self.
  • #delete: Removes the given object from self if self includes the object; returns self.
  • #delete?: Like #delete, but returns nil if the object is not in self.
  • #delete_if: Calls the block with each element in self; removes the element if the block returns a truthy value.
  • #keep_if: Calls the block with each element in self, deleting the element if the block returns false or nil; returns self.
  • #reject! Like #delete_if, but returns nil if no changes were made.
  • #select! (aliased as #filter!): Like #keep_if, but returns nil if no changes were made.
  • #subtract: Deletes from self every element found in the given enumerable; returns self:

Methods for Converting

  • #classify: Returns a hash that partitions the elements, as determined by the given block.
  • #collect! (aliased as #map!): Replaces each element with a block return-value.
  • #divide: Returns a set of sets that partition the elements, as determined by the given block.
  • #flatten: Returns a new set that is a recursive flattening of self.
  • #flatten!: Like #flatten, but if any changes were made replaces self with the result and returns self.
  • #inspect (aliased as #to_s): Returns a string representation of self.
  • #join: Returns the string formed by joining the string-converted elements of self with the given separator.
  • #to_a: Returns an array containing the elements of self.
  • #to_set: With a block given, creates and returns a new set; calls the block with each element of self, and adds the block's returns value to the new set.

Other Methods

  • #compare_by_identity: Sets self to compare by object identity (rather than by object content).
  • #each: Calls the block with each successive element of self; returns self.
  • #reset: Resets the internal state; useful if an element has been modified while an element in the set.

Class Method Summary

Instance Attribute Summary

Instance Method Summary

::Enumerable - Included

#all?

Returns whether every element meets a given criterion.

#any?

Returns whether any element meets a given criterion.

#chain

Returns an enumerator object generated from this enumerator and given enumerables.

#chunk

Each element in the returned enumerator is a 2-element array consisting of:

#chunk_while

Creates an enumerator for each chunked elements.

#collect

Alias for Enumerable#map.

#collect_concat
#compact

Returns an array of all non-+nil+ elements:

#count

Returns the count of elements, based on an argument or block criterion, if given.

#cycle

When called with positive integer argument n and a block, calls the block with each element, then does so again, until it has done so n times; returns nil:

#detect

Alias for Enumerable#find.

#drop

For positive integer n, returns an array containing all but the first n elements:

#drop_while

Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements after that point:

#each_cons

Calls the block with each successive overlapped +n+-tuple of elements; returns self:

#each_entry

Calls the given block with each element, converting multiple values from yield to an array; returns self:

#each_slice

Calls the block with each successive disjoint +n+-tuple of elements; returns self:

#each_with_index

Invoke self.each with *args.

#each_with_object

Calls the block once for each element, passing both the element and the given object:

#entries

Alias for Enumerable#to_a.

#filter

Returns an array containing elements selected by the block.

#filter_map

Returns an array containing truthy elements returned by the block.

#find

Returns the first element for which the block returns a truthy value.

#find_all
#find_index

Returns the index of the first element that meets a specified criterion, or nil if no such element is found.

#first

Returns the first element or elements.

#flat_map

Returns an array of flattened objects returned by the block.

#grep

Returns an array of objects based elements of self that match the given pattern.

#grep_v

Returns an array of objects based on elements of self that don't match the given pattern.

#group_by

With a block given returns a hash:

#include?
#inject

Returns the result of applying a reducer to an initial value and the first element of the ::Enumerable.

#lazy

Returns an ::Enumerator::Lazy, which redefines most ::Enumerable methods to postpone enumeration and enumerate values only on an as-needed basis.

#map

Returns an array of objects returned by the block.

#max

Returns the element with the maximum element according to a given criterion.

#max_by

Returns the elements for which the block returns the maximum values.

#member?

Returns whether for any element object == element:

#min

Returns the element with the minimum element according to a given criterion.

#min_by

Returns the elements for which the block returns the minimum values.

#minmax

Returns a 2-element array containing the minimum and maximum elements according to a given criterion.

#minmax_by

Returns a 2-element array containing the elements for which the block returns minimum and maximum values:

#none?

Returns whether no element meets a given criterion.

#one?

Returns whether exactly one element meets a given criterion.

#partition

With a block given, returns an array of two arrays:

#reduce
#reject

Returns an array of objects rejected by the block.

#reverse_each

With a block given, calls the block with each element, but in reverse order; returns self:

#select
#slice_after

Creates an enumerator for each chunked elements.

#slice_before

With argument pattern, returns an enumerator that uses the pattern to partition elements into arrays ("slices").

#slice_when

Creates an enumerator for each chunked elements.

#sort

Returns an array containing the sorted elements of self.

#sort_by

With a block given, returns an array of elements of self, sorted according to the value returned by the block for each element.

#sum

With no block given, returns the sum of initial_value and the elements:

#take

For non-negative integer n, returns the first n elements:

#take_while

Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements up to that point:

#tally

When argument #hash is not given, returns a new hash whose keys are the distinct elements in self; each integer value is the count of occurrences of each element:

#to_a

Returns an array containing the items in self:

#to_h

When self consists of 2-element arrays, returns a hash each of whose entries is the key-value pair formed from one of those arrays:

#to_set

Makes a set from the enumerable object with given arguments.

#uniq

With no block, returns a new array containing only unique elements; the array has no two elements e0 and e1 such that e0.eql?(e1):

#zip

With no block given, returns a new array new_array of size self.size whose elements are arrays.

Constructor Details

.new(object = nil) ⇒ Set .new(object = nil) {|element| ... } ⇒ Set

Returns a new Set object based on the given object, which must be an ::Enumerable or nil.

With argument object given as nil, returns a new empty Set object:

Set.new                          # => Set[]
Set.new { fail 'Cannot happen' } # => Set[]  # Block not called.

With no block given and enumerable argument object given, populates the new set with the elements of object:

Set.new(%w[ a b c ])      # => Set["a", "b", "c"]
Set.new({foo: 0, bar: 1}) # => Set[[:foo, 0], [:bar, 1]]
Set.new(4..10)            # => Set[4, 5, 6, 7, 8, 9, 10]
Set.new(Dir.new('lib')).take(5)
# => [".", "..", "bundled_gems.rb", "bundler", "bundler.rb"]
Set.new(File.new('doc/NEWS/NEWS-4.0.0.md')).take(3)
# => ["# NEWS for Ruby 4.0.0\n", "\n", "This document is a list of user-visible feature changes\n"]

With a block given and enumerable argument object given, calls the block with each element of object; adds the block's return value to the new set:

Set.new(4..10) {|i| i * 2 } # => Set[8, 10, 12, 14, 16, 18, 20]

Related: see Methods for Creating a Set.

[ GitHub ]

  
# File 'set.c', line 535

static VALUE
set_i_initialize(int argc, VALUE *argv, VALUE set)
{
    if (RBASIC(set)->flags & RSET_INITIALIZED) {
        rb_raise(rb_eRuntimeError, "cannot reinitialize set");
    }
    RBASIC(set)->flags |= RSET_INITIALIZED;

    VALUE other;
    rb_check_arity(argc, 0, 1);

    if (argc > 0 && (other = argv[0]) != Qnil) {
        if (RB_TYPE_P(other, T_ARRAY)) {
            long i;
            int block_given = rb_block_given_p();
            set_table *into = RSET_TABLE(set);
            for (i=0; i<RARRAY_LEN(other); i++) {
                VALUE key = RARRAY_AREF(other, i);
                if (block_given) key = rb_yield(key);
                set_table_insert_wb(into, set, key);
            }
        }
        else {
            rb_block_call(other, enum_method_id(other), 0, 0,
                rb_block_given_p() ? set_initialize_with_block : set_initialize_without_block,
                set);
        }
    }

    return set;
}

Class Method Details

.[](*objects) ⇒ Set

Returns a new Set object populated with the given objects:

Set[1, 'one', :one, 1.0, %w[a b c], {foo: 0, bar: 1}]
# => Set[1, "one", :one, 1.0, ["a", "b", "c"], {foo: 0, bar: 1}]
Set[Set[0, 1, 2], Set[%w[a b c]]]
# => Set[Set[0, 1, 2], Set[["a", "b", "c"]]]
Set[] # => Set[]

Related: see Methods for Creating a Set.

[ GitHub ]

  
# File 'set.c', line 430

static VALUE
set_s_create(int argc, VALUE *argv, VALUE klass)
{
    VALUE set = set_alloc_with_size(klass, argc);
    set_table *table = RSET_TABLE(set);
    int i;

    for (i=0; i < argc; i++) {
        set_table_insert_wb(table, set, argv[i]);
    }

    return set;
}

Instance Attribute Details

#compare_by_identityself (readonly)

Sets self to compare by object identity (rather than by object content, which is the initial setting); returns self:

set = Set.new
set.compare_by_identity
str = +"foo"
set.add(str)
# =>  Set["foo"]
set.include?(str)
# => true
set.add(str)
# => Set["foo"])
set.include?(+"foo")
# => false
set.add(+"foo")
# => Set["foo", "foo"])

Once set, the compare-by-identity property may not be unset.

Related: #compare_by_identity?.

[ GitHub ]

  
# File 'set.c', line 1360

static VALUE
set_i_compare_by_identity(VALUE set)
{
    if (RSET_COMPARE_BY_IDENTITY(set)) return set;

    if (set_iterating_p(set)) {
        rb_raise(rb_eRuntimeError, "compare_by_identity during iteration");
    }

    return set_reset_table_with_type(set, &identhash);
}

#compare_by_identity?Boolean (readonly)

Returns whether self compares elements by object identity (rather than by content):

set = Set[]
set.compare_by_identity? # => false
set.compare_by_identity
set.compare_by_identity? # => true

Related: #compare_by_identity; see also Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1387

static VALUE
set_i_compare_by_identity_p(VALUE set)
{
    return RBOOL(RSET_COMPARE_BY_IDENTITY(set));
}

#empty?Boolean (readonly)

Returns whether self contains no elements:

Set[].empty?  # => true
Set[0].empty? # => false

Related: see Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1420

static VALUE
set_i_empty(VALUE set)
{
    return RBOOL(RSET_EMPTY(set));
}

Instance Method Details

#&(enumerable) ⇒ Set Also known as: #intersection

Returns a new set containing the intersection of self and enumerable; that is, containing all elements common to both, with no duplicates. Argument enumerable must be an ::Enumerable object:

set = Set[*(0..6), *%w[ a b c]] # => Set[0, 1, 2, 3, 4, 5, 6, "a", "b", "c"]
set & ['c', 6, 8, 4]            # => Set["c", 6, 4]
set & [:foo, :bar]              # => Set[]  # No elements in common.

Related: see Methods for Set Operations.

[ GitHub ]

  
# File 'set.c', line 1161

static VALUE
set_i_intersection(VALUE set, VALUE other)
{
    VALUE new_set = set_s_alloc(rb_obj_class(set));
    set_table *stable = RSET_TABLE(set);
    set_table *ntable = RSET_TABLE(new_set);

    if (rb_obj_is_kind_of(other, rb_cSet)) {
        set_table *otable = RSET_TABLE(other);
        if (set_table_size(stable) >= set_table_size(otable)) {
            /* Swap so we iterate over the smaller set */
            otable = stable;
            set = other;
        }

        struct set_intersection_data data = {
            .set = new_set,
            .into = ntable,
            .other = otable
        };
        set_iter(set, set_intersection_i, (st_data_t)&data);
    }
    else {
        struct set_intersection_data data = {
            .set = new_set,
            .into = ntable,
            .other = stable
        };
        rb_block_call(other, enum_method_id(other), 0, 0, set_intersection_block, (VALUE)&data);
    }

    return new_set;
}

#+(enumerable) ⇒ Set Also known as: #|, #union

Returns a new Set object containing the union of self and the given enumerable; that is, containing the elements of both self and enumerable.

set = Set[0, 1, 2]
set | Set[2, 1, 'a'] # => Set[0, 1, 2, "a"]
set | set            # => Set[0, 1, 2]

Related: see Methods for Set Operations.

[ GitHub ]

  
# File 'set.c', line 1493

static VALUE
set_i_union(VALUE set, VALUE other)
{
    set = rb_obj_dup(set);
    set_merge_enum_into(set, other);
    return set;
}

#-(enumerable) ⇒ Set Also known as: #difference

Returns a new set containing the difference of self and argument enumerable; that is, containing all elements in self that are not in enumerable.

set = Set[*(0..6), *%w[ a b c]] # => Set[0, 1, 2, 3, 4, 5, 6, "a", "b", "c"]
set - ['b', 6, 4, 1]            # => Set[0, 2, 3, 5, "a", "c"]
set - ['d', 7, 9]               # => Set[0, 1, 2, 3, 4, 5, 6, "a", "b", "c"]

Related: see Methods for Set Operations.

[ GitHub ]

  
# File 'set.c', line 1564

static VALUE
set_i_difference(VALUE set, VALUE other)
{
    return set_i_subtract(rb_obj_dup(set), other);
}

#<(other_set) ⇒ Boolean Also known as: #proper_subset?

Returns whether self is a proper subset of the given other_set:

set = Set[*'b'..'e']
set.proper_subset?(set)            # => false
set.proper_subset?(Set[*'a'..'f']) # => true

Related: Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1909

static VALUE
set_i_proper_subset(VALUE set, VALUE other)
{
    check_set(other);
    if (RSET_SIZE(set) >= RSET_SIZE(other)) return Qfalse;
    return set_le(set, other);
}

#<<(object) ⇒ self Also known as: #add

Adds the given object to self, returns self:

set = Set[0, 1, 2]
set.add(%w[a b c]) # => Set[0, 1, 2, ["a", "b", "c"]]
set.add(0)         # => Set[0, 1, 2, ["a", "b", "c"]]

Related: see Methods for Assigning.

[ GitHub ]

  
# File 'set.c', line 760

static VALUE
set_i_add(VALUE set, VALUE item)
{
    rb_check_frozen(set);
    if (set_iterating_p(set)) {
        if (!set_table_lookup(RSET_TABLE(set), (st_data_t)item)) {
            no_new_item();
        }
    }
    else {
        set_insert_wb(set, item);
    }
    return set;
}

#<=(other_set) ⇒ Boolean Also known as: #subset?

Returns whether self is a subset of the given other_set:

set = Set[*'b'..'e']
set.subset?(set)            # => true
set.subset?(Set[*'a'..'f']) # => true
set.subset?(Set[*'c'..'e']) # => false

Related: Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1931

static VALUE
set_i_subset(VALUE set, VALUE other)
{
    check_set(other);
    if (RSET_SIZE(set) > RSET_SIZE(other)) return Qfalse;
    return set_le(set, other);
}

#<=>(object) ⇒ 1, ...

Compares self and object.

If object is another set, returns:

  • -1, if self is a proper subset of object.
  • 0, if self and object have the same elements.
  • 1, if self is a proper superset of object.
  • nil, if none of the above; that is, if self and object each have one or more elements not included in the other.

Examples:

set = Set[0, 1, 2]
set <=> Set[3, 2, 1, 0] # => -1
set <=> Set[2, 1, 0]    # => 0
set <=> Set[1, 0]       # => 1
set <=> Set[1, 0, 3]    # => nil

Returns nil if object is not a set:

set <=> [2, 1, 0] # => nil  # Array, not Set.

Related: see Methods for Comparing.

[ GitHub ]

  
# File 'set.c', line 2083

static VALUE
set_i_compare(VALUE set, VALUE other)
{
    if (rb_obj_is_kind_of(other, rb_cSet)) {
        size_t set_size = RSET_SIZE(set);
        size_t other_size = RSET_SIZE(other);

        if (set_size < other_size) {
            if (set_le(set, other) == Qtrue) {
                return INT2NUM(-1);
            }
        }
        else if (set_size > other_size) {
            if (set_le(other, set) == Qtrue) {
                return INT2NUM(1);
            }
        }
        else if (set_le(set, other) == Qtrue) {
            return INT2NUM(0);
        }
    }

    return Qnil;
}

#==(object) ⇒ Boolean Also known as: #eql?

Returns whether object is a set, and has the same elements as self:

set = Set[0, 1, 2]
set == Set[1, 2, 0]   # => true
set == [1, 2, 3]      # => false
set == Set[1, 2, '3'] # => false

Related: see Methods for Comparing.

[ GitHub ]

  
# File 'set.c', line 2148

static VALUE
set_i_eq(VALUE set, VALUE other)
{
    if (!rb_obj_is_kind_of(other, rb_cSet)) return Qfalse;
    if (set == other) return Qtrue;

    set_table *stable = RSET_TABLE(set);
    set_table *otable = RSET_TABLE(other);
    size_t ssize = set_table_size(stable);
    size_t osize = set_table_size(otable);

    if (ssize != osize) return Qfalse;
    if (ssize == 0 && osize == 0) return Qtrue;
    if (stable->type != otable->type) return Qfalse;

    struct set_equal_data data;
    data.set = other;
    return rb_exec_recursive_paired(set_recursive_eql, set, other, (VALUE)&data);
}

#===(object) ⇒ Boolean Also known as: #include?, #member?

Returns whether the given object is an element of self:

set = [0, :zero, '0']
set.include?('0')    # => true
set.include?('zero') # => false

Tests equality using #hash and #eql?.

Aliased as #===, which means that sets may be used in case expressions:

case :apple
when Set[:potato, :carrot]
'vegetable'
when Set[:apple, :banana]
'fruit'
else
'unknown'
end
# => "fruit"

Related: see Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1221

static VALUE
set_i_include(VALUE set, VALUE item)
{
    return RBOOL(RSET_IS_MEMBER(set, item));
}

#>(other_set) ⇒ Boolean Also known as: #proper_superset?

Returns whether self is a proper superset of the given other_set:

set = Set[*'a'..'f']
set.proper_superset?(set)            # => false
set.proper_superset?(Set[*'b'..'e']) # => true

Related: Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1953

static VALUE
set_i_proper_superset(VALUE set, VALUE other)
{
    check_set(other);
    if (RSET_SIZE(set) <= RSET_SIZE(other)) return Qfalse;
    return set_le(other, set);
}

#>=(other_set) ⇒ Boolean Also known as: #superset?

Returns whether self is a superset of the given other_set:

set = Set[*'a'..'f']          # => Set["a", "b", "c", "d", "e", "f"]
set.superset?(set)            # => true
set.superset?(Set[*'b'..'e']) # => true
set.superset?(Set[*'b'..'x']) # => false

Related: Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1975

static VALUE
set_i_superset(VALUE set, VALUE other)
{
    check_set(other);
    if (RSET_SIZE(set) < RSET_SIZE(other)) return Qfalse;
    return set_le(other, set);
}

#^(enumerable) ⇒ Set

Returns a new Set object containing the exclusive OR of self and the given enumerable; that is, containing each element that is in either self or enumerable, but not in both:

set = Set[0, 1, 2]
set ^ Set[1, 2, 3]        # => Set[0, 3]
set ^ Set[2, 1]           # => Set[0]
set ^ Set[2, *('a'..'c')] # => Set[0, 1, "a", "b", "c"]
set ^ Set[2, 1, 0]        # => Set[]

For Set set and Enumerable enumerable, these expressions are equivalent:

set ^ enumerable
((set | enumerable) - (set & enumerable))

Related: see Methods for Set Operations.

[ GitHub ]

  
# File 'set.c', line 1461

static VALUE
set_i_xor(VALUE set, VALUE other)
{
    VALUE new_set = rb_obj_dup(set);

    if (rb_obj_is_kind_of(other, rb_cSet)) {
        set_iter(other, set_xor_i, (st_data_t)new_set);
    }
    else {
        VALUE tmp = set_s_alloc(rb_cSet);
        set_merge_enum_into(tmp, other);
        set_iter(tmp, set_xor_i, (st_data_t)new_set);
    }

    return new_set;
}

#<<(object) ⇒ self #add(object) ⇒ self

Alias for #<<.

#add?(object) ⇒ self?

Like #add, but returns nil if the given object is already in self:

set = Set[0, 1, 2]
set.add?(:foo)   # => Set[0, 1, 2, :foo]
set.add?(0..9) # => Set[0, 1, 2, :foo, 0..9]
set.add?(2) # => nil

Related: see Methods for Assigning.

[ GitHub ]

  
# File 'set.c', line 788

static VALUE
set_i_add_p(VALUE set, VALUE item)
{
    rb_check_frozen(set);
    if (set_iterating_p(set)) {
        if (!set_table_lookup(RSET_TABLE(set), (st_data_t)item)) {
            no_new_item();
        }
        return Qnil;
    }
    else {
        return set_insert_wb(set, item) ? Qnil : set;
    }
}

#classify {|element| ... } ⇒ Hash #classifyEnumerator

With a block given, calls the block with each element of self; returns a hash whose keys are the block's return values. The value for each key is a set containing the elements for which the block returned that key.

This example classifies elements by their classes:

set = Set[*(5..7), *%w[foo bar]] # => Set[5, 6, 7, "foo", "bar"]
set.classify {|element| element.class }
# => {Integer => Set[5, 6, 7], String => Set["foo", "bar"]}

With no block given, returns an ::Enumerator.

Related: see Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 950

static VALUE
set_i_classify(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
    VALUE args[2];
    args[0] = rb_hash_new();
    args[1] = rb_obj_class(set);
    set_iter(set, set_classify_i, (st_data_t)args);
    return args[0];
}

#clearself

Returns self with all elements removed:

Set[1, :one, 'one', 1.0].clear # => Set[]

Related: see Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 1107

static VALUE
set_i_clear(VALUE set)
{
    rb_check_frozen(set);
    if (RSET_SIZE(set) == 0) return set;
    if (set_iterating_p(set)) {
        set_iter(set, set_clear_i, 0);
    }
    else {
        set_table_clear(RSET_TABLE(set));
        set_compact_after_delete(set);
    }
    return set;
}

#collect! {|element| ... } ⇒ self #collect!Enumerator

Alias for #map!.

#delete(object) ⇒ self

Removes the given object from self if self includes the object; returns self:

set = Set[0, 'zero', :zero]
set.delete(0)       # => Set["zero", :zero]
set.delete(:nosuch) # => Set["zero", :zero]

Related: see Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 816

static VALUE
set_i_delete(VALUE set, VALUE item)
{
    rb_check_frozen(set);
    if (set_table_delete(RSET_TABLE(set), (st_data_t *)&item)) {
        set_compact_after_delete(set);
    }
    return set;
}

#delete?(object) ⇒ self?

Like #delete, but returns nil if the object is not in self:

set = Set[0, 'zero', :zero]
set.delete?(0) # => Set["zero", :zero]
set.delete?(0) # => nil

Related: see Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 838

static VALUE
set_i_delete_p(VALUE set, VALUE item)
{
    rb_check_frozen(set);
    if (set_table_delete(RSET_TABLE(set), (st_data_t *)&item)) {
        set_compact_after_delete(set);
        return set;
    }
    return Qnil;
}

#delete_if {|element| ... } ⇒ self #delete_ifEnumerator

With a block given, calls the block with each element in self; removes the element if the block returns a truthy value:

set = Set[*0..9]
# => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
set.delete_if {|element| element.even? }
# => Set[1, 3, 5, 7, 9]

With no block given, returns an ::Enumerator.

Related: Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 872

static VALUE
set_i_delete_if(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
    rb_check_frozen(set);
    set_iter(set, set_delete_if_i, 0);
    set_compact_after_delete(set);
    return set;
}

#-(enumerable) ⇒ Set #difference(enumerable) ⇒ Set

Alias for #-.

#disjoint?(enumerable) ⇒ Boolean

Returns whether no element of enumerable is present in self:

set = Set[0, 'zero', :zero]
set.disjoint?([1, 2, 3])    # => true
set.disjoint?([0, 1, 2, 3]) # => false

Related: see Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 2048

static VALUE
set_i_disjoint(VALUE set, VALUE other)
{
    return RBOOL(!RTEST(set_i_intersect(set, other)));
}

#divide {|ele| ... } ⇒ Set #divide {|ele0, ele1| ... } ⇒ Set #divideEnumerator

With a block given, returns a set of sets.

For a block that accepts one argument, calls the block with each element; creates a set for each distinct block return value:

set = Set[*0..9]
# => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Divide into mod 3 sets.
set.divide {|ele| ele % 3 }
# => Set[Set[0, 3, 6, 9], Set[1, 4, 7], Set[2, 5, 8]]
# Divide into mod 5 sets.
set.divide {|ele| ele % 5 }
# => Set[Set[0, 5], Set[1, 6], Set[2, 7], Set[3, 8], Set[4, 9]]

Set[0].divide {|ele| anything } # => Set[Set[0]]
Set[].divide {|ele| not called } # => Set[]

For a block that accepts two arguments, divides self into connected components based on the binary relation defined by the block, calling the block with each 2-element permutation of the elements of self:

set = Set[*0..9]
# => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Divide into mod 2 sets.
set.divide {|i, j| (i - j) % 2 == 0 }
# => Set[Set[0, 2, 4, 6, 8], Set[1, 3, 5, 7, 9]]
# Divide into mod 3 sets.
set.divide {|i, j| (i - j) % 3 == 0 }
# => Set[Set[0, 3, 6, 9], Set[1, 4, 7], Set[2, 5, 8]]

Set[0].divide {|i, j| not called } # => Set[Set[0]]
Set[].divide {|i, j| not called } # => Set[]

With no block given, returns an ::Enumerator.

Related: see Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 1076

static VALUE
set_i_divide(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);

    if (rb_block_arity() == 2) {
        return set_divide_arity2(set);
    }

    VALUE values = rb_hash_values(set_i_classify(set));
    set = set_alloc_with_size(rb_cSet, RARRAY_LEN(values));
    set_merge_enum_into(set, values);
    return set;
}

#each {|element| ... } ⇒ self #eachEnumerator

With a block given, calls the block once for each element in the set, passing the element as a parameter; returns self:

sum = 0
Set[1, 2, 3].each {|i| sum += i }
sum => 6

With no block given, returns an ::Enumerator.

[ GitHub ]

  
# File 'set.c', line 1592

static VALUE
set_i_each(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
    set_iter(set, set_each_i, 0);
    return set;
}

#==(object) ⇒ Boolean #eql?(object) ⇒ Boolean

Alias for #==.

#select! {|element| ... } ⇒ self? #select!Enumerator
Also known as: #select!

With a block given, like #keep_if, but returns nil if no changes were made:

set = Set[*0..9]           # => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
set.select! {|i| i.even? } # => Set[0, 2, 4, 6, 8]
set.select! {|i| i.even? } # => nil
set.select! {|i| i.odd? }  # => Set[]

With no block given, returns an ::Enumerator.

Related: see Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 1689

static VALUE
set_i_select(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
    rb_check_frozen(set);

    set_table *table = RSET_TABLE(set);
    size_t n = set_table_size(table);
    set_iter(set, set_keep_if_i, (st_data_t)table);

    return (n == set_table_size(table)) ? Qnil : set;
}

#flattenSet

Returns a new set that is a copy of self, but with self and its nested sets flattened; that is, their elements become elements of self:

Set[Set[0, 1], Set[2, 3]].flatten
# => Set[0, 1, 2, 3]
Set[Set[0, 1], Set[Set[2, 3], Set[3, 4]]].flatten
# => Set[0, 1, 2, 3, 4]

Does not flatten nested arrays or hashes:

Set[%w[foo bar]].flatten      # => Set[["foo", "bar"]]
Set[{foo: 0, bar: 1}].flatten # => Set[{foo: 0, bar: 1}]

Related: see Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 1824

static VALUE
set_i_flatten(VALUE set)
{
    VALUE new_set = set_s_alloc(rb_obj_class(set));
    set_flatten_merge(new_set, set, rb_hash_new());
    return new_set;
}

#flatten!self?

Like #flatten, but if any changes were made replaces self with the result and returns self:

Set[Set[0, 1], Set[2, 3]].flatten!
# => Set[0, 1, 2, 3]
Set[Set[0, 1], Set[Set[2, 3], Set[3, 4]]].flatten!
# => Set[0, 1, 2, 3, 4]

Returns nil if no changes were made:

Set[0, 1, 2].flatten! # => nil

Related: see Methods for Assigning.

[ GitHub ]

  
# File 'set.c', line 1860

static VALUE
set_i_flatten_bang(VALUE set)
{
    bool contains_set = false;
    set_iter(set, set_contains_set_i, (st_data_t)&contains_set);
    if (!contains_set) return Qnil;
    rb_check_frozen(set);
    return set_i_replace(set, set_i_flatten(set));
}

#hashInteger

Returns the integer hash value for self.

Two sets with the same content have the same hash value.

Set[0, 1].hash == Set[1, 0].hash # => true
Set[0, 1].hash == Set[0].hash    # => false
[ GitHub ]

  
# File 'set.c', line 2188

static VALUE
set_i_hash(VALUE set)
{
    st_index_t size = RSET_SIZE(set);
    st_index_t hval = rb_st_hash_start(size);
    hval = rb_hash_uint(hval, (st_index_t)set_i_hash);
    if (size) {
        set_iter(set, set_hash_i, (VALUE)&hval);
    }
    hval = rb_st_hash_end(hval);
    return ST2FIX(hval);
}

#===(object) ⇒ Boolean #include?(object) ⇒ Boolean

Alias for #===.

#initialize_copy(other)

This method is for internal use only.
[ GitHub ]

  
# File 'set.c', line 568

static VALUE
set_i_initialize_copy(VALUE set, VALUE other)
{
    if (set == other) return set;

    if (set_iterating_p(set)) {
        rb_raise(rb_eRuntimeError, "cannot replace set during iteration");
    }

    struct set_object *sobj;
    TypedData_Get_Struct(set, struct set_object, &set_data_type, sobj);

    set_free_embedded_table(&sobj->table);
    set_copy(&sobj->table, RSET_TABLE(other));
    rb_gc_writebarrier_remember(set);

    return set;
}

#to_sString #inspectString

Alias for #to_s.

#intersect?(enumerable) ⇒ Boolean

Returns whether self and enumerable have any elements in common:

set = Set[0, 'zero', :zero]
set.intersect?([0, 1, 2])        # => true
set.intersect?(%w[zero one two]) # => true
set.intersect?(Set[3])           # => false

Related: see Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 2007

static VALUE
set_i_intersect(VALUE set, VALUE other)
{
    if (rb_obj_is_kind_of(other, rb_cSet)) {
        size_t set_size = RSET_SIZE(set);
        size_t other_size = RSET_SIZE(other);
        VALUE args[2];
        args[1] = Qfalse;
        VALUE iter_arg;

        if (set_size < other_size) {
            iter_arg = set;
            args[0] = (VALUE)RSET_TABLE(other);
        }
        else {
            iter_arg = other;
            args[0] = (VALUE)RSET_TABLE(set);
        }
        set_iter(iter_arg, set_intersect_i, (st_data_t)args);
        return args[1];
    }
    else if (rb_obj_is_kind_of(other, rb_mEnumerable)) {
        return rb_funcall(other, id_any_p, 1, set);
    }
    else {
        rb_raise(rb_eArgError, "value must be enumerable");
    }
}

#&(enumerable) ⇒ Set #intersection(enumerable) ⇒ Set

Alias for #&.

#join(separator = $,) ⇒ String

Returns the string formed by joining the string-converted elements of self with the given separator (defaults to $,):

$, # => nil
Set[*%w[foo bar baz]].join
# => "foobarbaz"
Set[*%w[foo bar baz]].join(', ')
# => "foo, bar, baz"

Flattens nested arrays:

Set[[:foo, [:bar, [:baz, :bat]]]].join
# => "foobarbazbat"

Does not flatten nested sets:

Set[Set[:foo, Set[:bar, Set[:baz, :bat]]]].join
# => "Set[:foo, Set[:bar, Set[:baz, :bat]]]"

Related: see Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 741

static VALUE
set_i_join(int argc, VALUE *argv, VALUE set)
{
    rb_check_arity(argc, 0, 1);
    return rb_ary_join(set_i_to_a(set), argc == 0 ? Qnil : argv[0]);
}

#keep_if {|element| ... } ⇒ self #keep_ifEnumerator

With a block given, calls the block with each element in self, deleting the element if the block returns false or nil; returns self:

set = Set[*0..9]           # => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
set.keep_if {|i| i.even? } # => Set[0, 2, 4, 6, 8]
set.keep_if {|i| i.odd? }  # => Set[]

With no block given, returns an ::Enumerator.

Related: see Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 1662

static VALUE
set_i_keep_if(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
    rb_check_frozen(set);

    set_iter(set, set_keep_if_i, (st_data_t)RSET_TABLE(set));

    return set;
}

#lengthInteger Also known as: #size

Returns the number of elements in self:

Set[*0..9].size # => 10

Related: see Methods for Querying.

[ GitHub ]

  
# File 'set.c', line 1403

static VALUE
set_i_size(VALUE set)
{
    return RSET_SIZE_NUM(set);
}

#collect! {|element| ... } ⇒ self #collect!Enumerator
Also known as: #collect!

With a block given, calls the block with each element in self; replaces the element with the block's return value:

Set[1, :one, 'one', 1.0].collect! {|element| element.class }
# => Set[Integer, Symbol, String, Float]

With no block given, returns an ::Enumerator.

Related: see Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 1622

static VALUE
set_i_collect(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
    rb_check_frozen(set);

    VALUE new_set = set_s_alloc(rb_obj_class(set));
    set_iter(set, set_collect_i, (st_data_t)new_set);
    set_i_initialize_copy(set, new_set);

    return set;
}

#===(object) ⇒ Boolean #member?(object) ⇒ Boolean

Alias for #===.

#merge(*enumerables, **nil) ⇒ self

Adds each element of each of the given enumerables to self; returns self:

set = Set[*0..2]                 # => Set[0, 1, 2]
set.merge('a'..'c', %w[foo bar]) # => Set[0, 1, 2, "a", "b", "c", "foo", "bar"]
set.merge('a'..'c', %w[foo bar]) # => Set[0, 1, 2, "a", "b", "c", "foo", "bar"]

Related: see Methods for Assigning.

[ GitHub ]

  
# File 'set.c', line 1284

static VALUE
set_i_merge(int argc, VALUE *argv, VALUE set)
{
    if (rb_keyword_given_p()) {
        rb_raise(rb_eArgError, "no keywords accepted");
    }

    if (set_iterating_p(set)) {
        rb_raise(rb_eRuntimeError, "cannot add to set during iteration");
    }

    rb_check_frozen(set);

    int i;

    for (i=0; i < argc; i++) {
        set_merge_enum_into(set, argv[i]);
    }

    return set;
}

#<(other_set) ⇒ Boolean #proper_subset?(other_set) ⇒ Boolean

Alias for #<.

#>(other_set) ⇒ Boolean #proper_superset?(other_set) ⇒ Boolean

Alias for #>.

#reject! {|element| ... } ⇒ self? #reject!Enumerator

With a block given, like #delete_if, but returns nil if no changes were made:

set = Set[*0..9]                       # => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
set.reject! {|element| element.even? } # => Set[1, 3, 5, 7, 9]
set.reject! {|element| element.even? } # => nil
set.reject! {|element| element.odd? }  # => Set[]

With no block given, returns an ::Enumerator.

Related: see Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 898

static VALUE
set_i_reject(VALUE set)
{
    RETURN_SIZED_ENUMERATOR(set, 0, 0, set_enum_size);
    rb_check_frozen(set);

    set_table *table = RSET_TABLE(set);
    size_t n = set_table_size(table);
    set_iter(set, set_delete_if_i, 0);

    if (n == set_table_size(table)) return Qnil;

    set_compact_after_delete(set);
    return set;
}

#replace(enumerable) ⇒ self

Replaces the contents self with the contents of the given enumerable; returns self:

set = Set[1, 'c', :s] # => Set[1, "c", :s]
set.replace([1, 2])   # => Set[1, 2]

Related: see Methods for Assigning.

[ GitHub ]

  
# File 'set.c', line 1714

static VALUE
set_i_replace(VALUE set, VALUE other)
{
    rb_check_frozen(set);

    if (rb_obj_is_kind_of(other, rb_cSet)) {
        set_i_initialize_copy(set, other);
    }
    else {
        if (set_iterating_p(set)) {
            rb_raise(rb_eRuntimeError, "cannot replace set during iteration");
        }

        // make sure enum is enumerable before calling clear
        enum_method_id(other);

        set_table_clear(RSET_TABLE(set));
        set_merge_enum_into(set, other);
    }

    return set;
}

#resetself

Resets the internal state of self; return self.

A set relies on the #hash results of each element being consistent. Modifying an element in a way that changes the results of #hash may allow duplicate elements in the set:

array = [1]
set = Set[array]  # => Set[[1]]
array << 2
set.add(array)    # => Set[[1, 2], [1, 2]]

Calling #reset will recalculate all of the hash values and remove duplicate elements:

set.reset         # => Set[[1, 2]]
[ GitHub ]

  
# File 'set.c', line 1758

static VALUE
set_i_reset(VALUE set)
{
    if (set_iterating_p(set)) {
        rb_raise(rb_eRuntimeError, "reset during iteration");
    }

    return set_reset_table_with_type(set, RSET_TABLE(set)->type);
}

#select! {|element| ... } ⇒ self? #select!Enumerator

Alias for #filter!.

#lengthInteger #sizeInteger

Alias for #length.

#<=(other_set) ⇒ Boolean #subset?(other_set) ⇒ Boolean

Alias for #<=.

#subtract(enumerable) ⇒ self

Deletes from self every element found in the given enumerable; returns self:

set = Set[*0..9]        # => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
set.subtract(5..14)     # => Set[0, 1, 2, 3, 4]
set.subtract(Set[6, 2]) # => Set[0, 1, 3, 4]

Related: see Methods for Deleting.

[ GitHub ]

  
# File 'set.c', line 1540

static VALUE
set_i_subtract(VALUE set, VALUE other)
{
    rb_check_frozen(set);
    set_remove_enum_from(set, other);
    return set;
}

#>=(other_set) ⇒ Boolean #superset?(other_set) ⇒ Boolean

Alias for #>=.

#to_aArray

Returns an array containing the elements of self:

Set[1, 2].to_a       # => [1, 2]
Set[1, 'c', :s].to_a # => [1, "c", :s]

Related: Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 657

static VALUE
set_i_to_a(VALUE set)
{
    st_index_t size = RSET_SIZE(set);
    VALUE ary = rb_ary_new_capa(size);

    if (size == 0) return ary;

    if (ST_DATA_COMPATIBLE_P(VALUE)) {
        RARRAY_PTR_USE(ary, ptr, {
            size = set_keys(RSET_TABLE(set), ptr, size);
        });
        rb_gc_writebarrier_remember(ary);
        rb_ary_set_len(ary, size);
    }
    else {
        set_iter(set, set_to_a_i, (st_data_t)ary);
    }
    return ary;
}

#to_sString Also known as: #inspect

Returns a string representation of self:

Set[*%w[foo bar], {foo: 0, bar: 1}].inspect
# => "Set[\"foo\", \"bar\", {foo: 0, bar: 1}]"

Related: see Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 633

static VALUE
set_i_inspect(VALUE set)
{
    return rb_exec_recursive(set_inspect, set, 0);
}

#to_set {|element| ... } ⇒ Set #to_setself, Set

With a block given, creates and returns a new set; calls the block with each element of self, and adds the block's returns value to the new set:

set = Set[*0..9]        # => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
set.to_set {|i| i * 2 } # => Set[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

With no block given, when self is an instance of Set, returns self:

set = Set[*0..9]
set.to_set
set.to_set.equal?(set) # => true

With no block given, when self is an instance of a subclass of Set, returns a Set object containing the elements of self:

class MySet < Set; end
my_set = MySet[*0..9] # => #<MySet: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}>
set = my_set.to_set   # => Set[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Related: see Methods for Converting.

[ GitHub ]

  
# File 'set.c', line 706

static VALUE
set_i_to_set(VALUE set)
{
    if (rb_obj_is_instance_of(set, rb_cSet) && !rb_block_given_p()) {
        return set;
    }

    return rb_funcall_passing_block(rb_cSet, id_new, 1, &set);
}

#+(enumerable) ⇒ Set #union(enumerable) ⇒ Set

Alias for #+.

#+(enumerable) ⇒ Set #|(enumerable) ⇒ Set

Alias for #+.