class Set
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.
-
Equality of elements is determined according to
Object#eql?andObject#hash. UseSet#compare_by_identityto make a set compare its elements by their identity. -
Set assumes that the identity of each element does not change while it is stored. Modifying an element of a set will render the set to an unreliable state.
-
When a string is to be stored, a frozen copy of the string is stored instead unless the original string is already frozen.
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
-
Akinori MUSHA <knu@iDaemons.org> (current maintainer)
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:
-
Inherits from class Object.
-
Includes module Enumerable, which provides dozens of additional methods.
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 asintersection): Returns a new set containing the intersection ofselfand the given enumerable. -
-(aliased asdifference): Returns a new set containing the difference ofselfand the given enumerable. -
^: Returns a new set containing the exclusive OR ofselfand the given enumerable. -
|(aliased asunionand+): Returns a new set containing the union ofselfand the given enumerable.
Methods for Comparing
-
<=>: Returns -1, 0, or 1 asselfis less than, equal to, or greater than a given object. -
==: Returns whetherselfand a given enumerable are equal, as determined byObject#eql?.
Methods for Querying
-
compare_by_identity?: Returns whether the set considers only identity when comparing elements. -
empty?: Returns whether the set has no elements. -
include?(aliased asmember?and===): Returns whether a given object is an element in the set. -
subset?(aliased as<=): Returns whether a given object is a subset of the set. -
proper_subset?(aliased as<): Returns whether a given enumerable is a proper subset of the set. -
superset?(aliased as>=): Returns whether a given enumerable is a superset of the set. -
proper_superset?(aliased as>): Returns whether a given enumerable is a proper superset of the set. -
disjoint?: Returnstrueif the set and a given enumerable have no common elements,falseotherwise. -
intersect?: Returnstrueif the set and a given enumerable: have any common elements,falseotherwise.
Methods for Assigning
-
add(aliased as<<): Adds the given object toself, returnsself. -
add?: Likeadd, but returnsnilif the given object is already inself. -
merge: Adds the elements of the given enumerables toself; returnsself. -
replace: Replaces the contents ofselfwith the contents of the given enumerable; returnsself.
Methods for Deleting
-
clear: Removes all elements in the set; returnsself. -
delete: Removes a given object from the set; returnsself. -
delete?: If the given object is an element in the set, removes it and returnsself; otherwise, returnsnil. -
subtract: Removes each given object from the set; returnsself. -
delete_if- Removes elements specified by a given block. -
select!(aliased asfilter!): Removes elements not specified by a given block. -
keep_if: Removes elements not specified by a given block. -
reject!Removes elements specified by a given block.
Methods for Converting
-
classify: Returns a hash that partitions the elements, as determined by the given block. -
collect!(aliased asmap!): 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 ofself. -
flatten!: Replaces each nested set inselfwith the elements from that set. -
inspect(aliased asto_s): Returns a string displaying the elements. -
join: Returns a string containing all elements, converted to strings as needed, and joined by the given record separator. -
to_a: Returns an array containing all set elements. -
to_set: Returnsselfif given no arguments and no block; with a block given, returns a new set consisting of block return values.
Methods for Iterating
-
each: Calls the block with each successive element; returnsself.
Other Methods
-
compare_by_identity: Setsselfto compare by object identity (rather than by object content). -
reset: Resets the internal state; useful if an element has been modified while an element in the set.
Public Class Methods
[X] (*X) → Set[X]
Source
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;
}
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.
Source
# File ext/json/lib/json/add/set.rb, line 9 def self.json_create(object) new object['a'] end
See as_json.
(_Each[A]) → untyped
[X] (_Each[X]) { (X) → A } → untyped
(?nil) → untyped
Source
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;
}
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.
Public Instance Methods
(_Each[A]) → self
Source
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;
}
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.
(_Each[A]) → self
Source
static VALUE
set_i_difference(VALUE set, VALUE other)
{
return set_i_subtract(rb_obj_dup(set), other);
}
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.
(self) → bool
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;
}
Compares self and object.
If object is another set, returns:
-
-1, ifselfis a proper subset ofobject. -
0, ifselfandobjecthave the same elements. -
1, ifselfis a proper superset ofobject. -
nil, if none of the above; that is, ifselfandobjecteach 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.
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);
}
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.
(self) → bool
(_Each[A]) → self
Source
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;
}
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.
(_Each[A]) → self
Source
static VALUE
set_i_union(VALUE set, VALUE other)
{
set = rb_obj_dup(set);
set_merge_enum_into(set, other);
return set;
}
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.
(A) → self
Source
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;
}
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.
(A) → self?
Source
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;
}
}
Like add, but returns nil if 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.
Source
# File ext/json/lib/json/add/set.rb, line 28 def as_json(*) { JSON.create_id => self.class.name, 'a' => to_a, } end
Methods Set#as_json and Set.json_create may be used to serialize and deserialize a Set object; see Marshal.
Method Set#as_json serializes self, returning a 2-element hash representing self:
require 'json/add/set' x = Set.new(%w/foo bar baz/).as_json # => {"json_class"=>"Set", "a"=>["foo", "bar", "baz"]}
Method JSON.create deserializes such a hash, returning a Set object:
Set.json_create(x) # => #<Set: {"foo", "bar", "baz"}>
Source
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];
}
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.
() → self
Source
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;
}
Returns self with all elements removed:
Set[1, :one, 'one', 1.0].clear # => Set[]
Related: see Methods for Deleting.
Source
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;
}
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.
() → self
Source
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);
}
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?.
() → bool
Source
static VALUE
set_i_compare_by_identity_p(VALUE set)
{
return RBOOL(RSET_COMPARE_BY_IDENTITY(set));
}
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.
(A) → self
Source
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;
}
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.
(A) → self?
Source
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;
}
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.
Source
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;
}
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.
(_Each[A]) → self
(Set[A] | Enumerable[A]) → bool
Source
static VALUE
set_i_disjoint(VALUE set, VALUE other)
{
return RBOOL(!RTEST(set_i_intersect(set, other)));
}
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.
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;
}
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.
Source
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;
}
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.
() → bool
Source
static VALUE
set_i_empty(VALUE set)
{
return RBOOL(RSET_EMPTY(set));
}
Returns whether self contains no elements:
Set[].empty? # => true Set[0].empty? # => false
Related: see Methods for Querying.
Source
# File ext/psych/lib/psych/core_ext.rb, line 23 def encode_with(coder) hash = {} each do |m| hash[m] = true end coder["hash"] = hash coder end
() → Set[untyped]
Source
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;
}
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.
() → self?
Source
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));
}
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.
Source
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);
}
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
(Hash::_Key) → bool
Source
static VALUE
set_i_include(VALUE set, VALUE item)
{
return RBOOL(RSET_IS_MEMBER(set, item));
}
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.
Source
# File ext/psych/lib/psych/core_ext.rb, line 32 def init_with(coder) replace(coder["hash"].keys) end
Source
static VALUE
set_i_inspect(VALUE set)
{
return rb_exec_recursive(set_inspect, set, 0);
}
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.
(Set[A] | Enumerable[A]) → bool
Source
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");
}
}
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.
(_Each[A]) → self
(?string separator) → String
Source
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]);
}
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.
Source
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;
}
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.
(*_Each[A]) → self
Source
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;
}
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.
(self) → bool
Source
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);
}
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.
(self) → bool
Source
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);
}
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.
Source
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;
}
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.
(_Each[A]) → self
Source
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;
}
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.
() → self
Source
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);
}
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]]
Source
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;
}
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.
() → Integer
Source
static VALUE
set_i_size(VALUE set)
{
return RSET_SIZE_NUM(set);
}
(self) → bool
Source
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);
}
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.
(_Each[A]) → self
Source
static VALUE
set_i_subtract(VALUE set, VALUE other)
{
rb_check_frozen(set);
set_remove_enum_from(set, other);
return set;
}
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.
(self) → bool
Source
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);
}
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.
() → Array[A]
Source
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;
}
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.
Source
# File ext/json/lib/json/add/set.rb, line 44 def to_json(*args) as_json.to_json(*args) end
Returns a JSON string representing self:
require 'json/add/set' puts Set.new(%w/foo bar baz/).to_json
Output:
{"json_class":"Set","a":["foo","bar","baz"]}
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);
}
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.