класс Set
Класс Set реализует коллекцию неупорядоченных значений без дубликатов. Это гибрид интуитивно понятных средств взаимодействия с Array и быстрого поиска Hash.
Set удобно использовать с объектами Enumerable (реализующими each). Большинство методов инициализации и бинарных операторов принимают универсальные объекты Enumerable в дополнение к множествам и массивам. Объект Enumerable можно преобразовать в Set с помощью метода to_set.
Для хранения Set использует структуру данных, аналогичную Hash, за исключением того, что в ней есть только ключи, но нет значений.
-
Равенство элементов определяется согласно
Object#eql?иObject#hash. ИспользуйтеSet#compare_by_identity, чтобы множество сравнивало элементы по их идентичности. -
Set предполагает, что идентичность каждого элемента не меняется, пока он хранится в множестве. Изменение элемента множества приведет к тому, что множество станет ненадежным.
-
При добавлении строки сохраняется ее замороженная копия, если исходная строка еще не заморожена.
Сравнение
Операторы сравнения <, >, <= и >= реализованы как сокращенные формы методов {proper_,}{subset?,superset?}. Оператор <=> отражает этот порядок или возвращает nil для множеств, в которых есть различные элементы (например, {x, y} и {x, z}).
Пример
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
Контакты
-
Akinori MUSHA <knu@iDaemons.org> (текущий сопровождающий)
Наследование от Set
До Ruby 4.0 (выпущенной в декабре 2025 года) Set имел другую, менее эффективную реализацию. Он был реализован заново на C, а поведение некоторых основных методов было скорректировано.
Для обратной совместимости при наследовании класса от Set подключается дополнительный модуль Set::SubclassCompatible, который делает поведение унаследованного класса и имена внутренних методов более похожими на те, что были до Ruby 4.0.
Это легко увидеть, например, по поведению метода inspect:
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
В новом коде, если обратная совместимость не требуется, рекомендуется наследоваться от Set::CoreSet, чтобы избежать подключения слоя «совместимости»:
class MyCoreSet < Set::CoreSet end p MyCoreSet[1, 2, 3] # prints "MyCoreSet[1, 2, 3]"
Методы Set
Сначала рассмотрим, что находится в других местах. Класс Set:
-
Наследуется от класса Object.
-
Подключает модуль Enumerable, который предоставляет десятки дополнительных методов.
В частности, у класса Set мало собственных методов для получения элементов и итерации. Вместо этого он использует методы из Enumerable.
Здесь представлены методы класса Set, полезные для:
Методы создания множества
-
::[]: Возвращает новое множество, содержащее заданные объекты. -
::new: Возвращает новое множество, содержащее либо заданные объекты (если блок не передан), либо значения, возвращенные вызванным блоком (если блок передан).
Методы для операций над множествами
-
|(также доступен под именамиunionи+): Возвращает новое множество, содержащее все элементы изselfи все элементы из заданного перечислимого объекта (без дубликатов). -
&(также доступен под именемintersection): Возвращает новое множество, содержащее все общие элементыselfи заданного перечислимого объекта. -
-(также доступен под именемdifference): Возвращает копиюselfбез всех элементов, присутствующих в заданном перечислимом объекте. -
^: Возвращает новое множество, содержащее все элементы изselfи заданного перечислимого объекта, за исключением общих для них элементов.
Методы сравнения
-
<=>: Возвращает -1, 0 или 1 в зависимости от того, меньше лиselfзаданного объекта, равно ему или больше него. -
==: Возвращает признак равенстваselfи заданного перечислимого объекта, определяемого с помощьюObject#eql?. -
compare_by_identity?: Возвращает признак того, что множество учитывает только идентичность при сравнении элементов.
Методы запросов
-
length(также доступен под именемsize): Возвращает количество элементов. -
empty?: Возвращает признак того, что множество не содержит элементов. -
include?(также доступен под именамиmember?и===): Возвращает признак того, что заданный объект является элементом множества. -
subset?(также доступен под именем<=): Возвращает признак того, что заданный объект является подмножеством этого множества. -
proper_subset?(также доступен под именем<): Возвращает признак того, что заданный перечислимый объект является собственным подмножеством этого множества. -
superset?(также доступен под именем>=): Возвращает признак того, что заданный перечислимый объект является надмножеством этого множества. -
proper_superset?(также доступен под именем>): Возвращает признак того, что заданный перечислимый объект является собственным надмножеством этого множества. -
disjoint?: Возвращаетtrue, если у множества и заданного перечислимого объекта нет общих элементов, иfalseв противном случае. -
intersect?: Возвращаетtrue, если у множества и заданного перечислимого объекта есть общие элементы, иfalseв противном случае. -
compare_by_identity?: Возвращает признак того, что множество учитывает только идентичность при сравнении элементов.
Методы добавления элементов
-
add(также доступен под именем<<): Добавляет заданный объект в множество; возвращаетself. -
add?: Если заданный объект не является элементом множества, добавляет его и возвращаетself; в противном случае возвращаетnil. -
merge: Добавляет в множество элементы каждого из заданных перечислимых объектов; возвращаетself. -
replace: Заменяет содержимое множества содержимым заданного перечислимого объекта.
Методы удаления элементов
-
clear: Удаляет все элементы множества; возвращаетself. -
delete: Удаляет заданный объект из множества; возвращаетself. -
delete?: Если заданный объект является элементом множества, удаляет его и возвращаетself; в противном случае возвращаетnil. -
subtract: Удаляет каждый заданный объект из множества; возвращаетself. -
delete_if- Удаляет элементы, указанные заданным блоком. -
select!(также доступен под именемfilter!): Удаляет элементы, не указанные заданным блоком. -
keep_if: Удаляет элементы, не указанные заданным блоком. -
reject!Удаляет элементы, указанные заданным блоком.
Методы преобразования
-
classify: Возвращает хеш, группирующий элементы согласно заданному блоку. -
collect!(также доступен под именемmap!): Заменяет каждый элемент значением, возвращенным блоком. -
divide: Возвращает хеш, группирующий элементы согласно заданному блоку; отличается отclassifyтем, что блок может принимать один или два аргумента. -
flatten: Возвращает новое множество, представляющее собой рекурсивно выровненноеself. -
flatten!: Заменяет каждое вложенное множество вselfэлементами этого множества. -
inspect(также доступен под именемto_s): Возвращает строку, отображающую элементы. -
join: Возвращает строку, содержащую все элементы, при необходимости преобразованные в строки и объединенные заданным разделителем записей. -
to_a: Возвращает массив, содержащий все элементы множества. -
to_set: Если аргументы и блок не заданы, возвращаетself; если задан блок, возвращает новое множество из значений, возвращенных блоком.
Методы итерации
-
each: Вызывает блок для каждого следующего элемента; возвращаетself.
Другие методы
-
reset: Сбрасывает внутреннее состояние; полезен, если объект был изменен, пока являлся элементом множества.
Публичные методы класса
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], NULL);
}
return set;
} Возвращает новый объект Set, заполненный заданными объектами. См. Set::new.
# File ext/json/lib/json/add/set.rb, line 9 def self.json_create(object) new object['a'] end
См. as_json.
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, NULL);
}
}
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;
} Создает новое множество, содержащее элементы заданного перечислимого объекта.
Если передан блок, элементы enum предварительно обрабатываются этим блоком.
Set.new([1, 2]) #=> Set[1, 2]
Set.new([1, 2, 1]) #=> Set[1, 2]
Set.new([1, 'c', :s]) #=> Set[1, "c", :s]
Set.new(1..5) #=> Set[1, 2, 3, 4, 5]
Set.new([1, 2, 3]) { |x| x * x } #=> Set[1, 4, 9]
Открытые методы экземпляра
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;
} Возвращает новое множество, содержащее элементы, общие для этого множества и заданного перечислимого объекта.
Set[1, 3, 5] & Set[3, 2, 1] #=> Set[3, 1] Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> Set["a", "b"]
static VALUE
set_i_difference(VALUE set, VALUE other)
{
return set_i_subtract(rb_obj_dup(set), other);
} Возвращает новое множество, созданное как копия этого множества, из которой удалён каждый элемент, встречающийся в заданном перечислимом объекте.
Set[1, 3, 5] - Set[1, 5] #=> Set[3] Set['a', 'b', 'z'] - ['a', 'c'] #=> Set["b", "z"]
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;
} Возвращает 0, если множества равны, -1 / 1, если это множество является собственным подмножеством / надмножеством заданного множества, или nil, если в каждом из них есть уникальные элементы.
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);
} Возвращает true, если два множества равны.
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;
} Возвращает новое множество, содержащее элементы, входящие только в одно из двух множеств: это множество и заданный перечислимый объект. (set ^ enum) эквивалентно ((set | enum) - (set & enum)).
Set[1, 2] ^ Set[2, 3] #=> Set[3, 1] Set[1, 'b', 'c'] ^ ['b', 'd'] #=> Set["d", 1, "c"]
static VALUE
set_i_union(VALUE set, VALUE other)
{
set = rb_obj_dup(set);
set_merge_enum_into(set, other);
return set;
} Возвращает новое множество, созданное путём объединения этого множества с элементами заданного перечислимого объекта.
Set[1, 2, 3] | Set[2, 4, 5] #=> Set[1, 2, 3, 4, 5] Set[1, 5, 'z'] | (1..6) #=> Set[1, 5, "z", 2, 3, 4, 6]
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, NULL);
}
return set;
} Добавляет заданный объект в множество и возвращает self. Чтобы добавить сразу несколько элементов, используйте Set#merge.
Set[1, 2].add(3) #=> Set[1, 2, 3] Set[1, 2].add([3, 4]) #=> Set[1, 2, [3, 4]] Set[1, 2].add(2) #=> Set[1, 2]
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, NULL) ? Qnil : set;
}
} Добавляет заданный объект в множество и возвращает self. Если объект уже есть в множестве, возвращает nil.
Set[1, 2].add?(3) #=> Set[1, 2, 3] Set[1, 2].add?([3, 4]) #=> Set[1, 2, [3, 4]] Set[1, 2].add?(2) #=> nil
# File ext/json/lib/json/add/set.rb, line 28
def as_json(*)
{
JSON.create_id => self.class.name,
'a' => to_a,
}
end Методы Set#as_json и Set.json_create можно использовать для сериализации и десериализации объекта Set; см. Marshal.
Метод Set#as_json сериализует self и возвращает хеш из двух элементов, представляющий self:
require 'json/add/set'
x = Set.new(%w/foo bar baz/).as_json
# => {"json_class"=>"Set", "a"=>["foo", "bar", "baz"]}
Метод JSON.create десериализует такой хеш и возвращает объект Set:
Set.json_create(x) # => #<Set: {"foo", "bar", "baz"}>
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];
} Классифицирует множество по возвращаемому заданным блоком значению и возвращает хеш пар {значение => множество элементов}. Блок вызывается один раз для каждого элемента множества, которому передаётся этот элемент.
files = Set.new(Dir.glob("*.rb"))
hash = files.classify { |f| File.mtime(f).year }
hash #=> {2000 => Set["a.rb", "b.rb"],
# 2001 => Set["c.rb", "d.rb", "e.rb"],
# 2002 => Set["f.rb"]}
Если блок не задан, возвращает перечислитель.
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;
} Удаляет все элементы и возвращает self.
set = Set[1, 'c', :s] #=> Set[1, "c", :s] set.clear #=> Set[] set #=> Set[]
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;
} Заменяет элементы значениями, возвращёнными collect. Если блок не задан, возвращает перечислитель.
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);
} Заставляет множество сравнивать элементы по их идентичности и возвращает self.
static VALUE
set_i_compare_by_identity_p(VALUE set)
{
return RBOOL(RSET_COMPARE_BY_IDENTITY(set));
} Возвращает true, если множество сравнивает элементы по их идентичности. См. также Set#compare_by_identity.
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;
} Удаляет заданный объект из множества и возвращает self. Чтобы удалить сразу несколько элементов, используйте subtract.
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;
} Удаляет заданный объект из множества и возвращает self. Если объекта нет в множестве, возвращает nil.
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;
} Удаляет каждый элемент множества, для которого блок возвращает true, и возвращает self. Если блок не задан, возвращает перечислитель.
static VALUE
set_i_disjoint(VALUE set, VALUE other)
{
return RBOOL(!RTEST(set_i_intersect(set, other)));
} Возвращает true, если у этого множества и заданного перечислимого объекта нет общих элементов. Этот метод противоположен intersect?.
Set[1, 2, 3].disjoint? Set[3, 4] #=> false Set[1, 2, 3].disjoint? Set[4, 5] #=> true Set[1, 2, 3].disjoint? [3, 4] #=> false Set[1, 2, 3].disjoint? 4..5 #=> true
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;
} Разбивает множество на набор подмножеств согласно общности, определяемой заданным блоком.
Если арность блока равна 2, элементы o1 и o2 считаются общими, когда и block.call(o1, o2), и block.call(o2, o1) возвращают true. В противном случае элементы o1 и o2 считаются общими, когда block.call(o1) == block.call(o2).
numbers = Set[1, 3, 4, 6, 9, 10, 11]
set = numbers.divide { |i,j| (i - j).abs == 1 }
set #=> Set[Set[1],
# Set[3, 4],
# Set[6],
# Set[9, 10, 11]]
Если блок не задан, возвращает перечислитель.
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;
} Вызывает заданный блок один раз для каждого элемента множества, передавая ему этот элемент. Если блок не задан, возвращает перечислитель.
static VALUE
set_i_empty(VALUE set)
{
return RBOOL(RSET_EMPTY(set));
} Возвращает true, если множество не содержит элементов.
# 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 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;
} Возвращает новое множество, являющееся копией этого множества, рекурсивно разворачивая каждое вложенное множество.
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));
} Эквивалентен Set#flatten, но заменяет получателем себя на месте результатом операции. Возвращает nil, если изменений не было.
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);
} Возвращает хеш-код множества.
static VALUE
set_i_include(VALUE set, VALUE item)
{
return RBOOL(RSET_IS_MEMBER(set, item));
} Возвращает true, если множество содержит заданный объект:
Set[1, 2, 3].include? 2 #=> true Set[1, 2, 3].include? 4 #=> false
Обратите внимание, что include? и member? проверяют равенство элементов не с помощью ==, как это делают другие перечислимые объекты.
Этот метод имеет псевдоним ===, поэтому его можно использовать в выражениях case:
case :apple when Set[:potato, :carrot] "vegetable" when Set[:apple, :banana] "fruit" end # => "fruit"
См. также Enumerable#include?
# File ext/psych/lib/psych/core_ext.rb, line 32 def init_with(coder) replace(coder["hash"].keys) end
static VALUE
set_i_inspect(VALUE set)
{
return rb_exec_recursive(set_inspect, set, 0);
} Возвращает новую строку, содержащую элементы множества:
s = Set.new s.inspect # => "Set[]" s.add(1) s.inspect # => "Set[1]" s.add(2) s.inspect # => "Set[1, 2]"
Связанный раздел: см. Методы преобразования.
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");
}
} Возвращает true, если у этого множества и заданного перечислимого объекта есть хотя бы один общий элемент.
Set[1, 2, 3].intersect? Set[4, 5] #=> false Set[1, 2, 3].intersect? Set[3, 4] #=> true Set[1, 2, 3].intersect? 4..5 #=> false Set[1, 2, 3].intersect? [3, 4] #=> true
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]);
} Возвращает строку, созданную преобразованием каждого элемента множества в строку.
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;
} Удаляет каждый элемент множества, для которого блок возвращает false, и возвращает self. Если блок не задан, возвращает перечислитель.
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;
} Объединяет элементы заданных перечислимых объектов с множеством и возвращает self.
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);
} Возвращает true, если это множество является собственным подмножеством заданного множества.
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);
} Возвращает true, если это множество является собственным надмножеством заданного множества.
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;
} Эквивалентен Set#delete_if, но возвращает nil, если изменений не было. Если блок не задан, возвращает перечислитель.
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;
} Заменяет содержимое множества содержимым заданного перечислимого объекта и возвращает self.
set = Set[1, 'c', :s] #=> Set[1, "c", :s] set.replace([1, 2]) #=> Set[1, 2] set #=> Set[1, 2]
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);
} Сбрасывает внутреннее состояние после изменения существующих элементов и возвращает self. Элементы будут проиндексированы заново, а дубликаты удалены.
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;
} Эквивалентен Set#keep_if, но возвращает nil, если изменений не было. Если блок не задан, возвращает перечислитель.
static VALUE
set_i_size(VALUE set)
{
return RSET_SIZE_NUM(set);
} Возвращает количество элементов.
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);
} Возвращает true, если это множество является подмножеством заданного множества.
static VALUE
set_i_subtract(VALUE set, VALUE other)
{
rb_check_frozen(set);
set_remove_enum_from(set, other);
return set;
} Удаляет каждый элемент, встречающийся в заданном перечислимом объекте, и возвращает self.
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);
} Возвращает true, если множество является надмножеством заданного множества.
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;
} Возвращает массив, содержащий все элементы множества.
Set[1, 2].to_a #=> [1, 2] Set[1, 'c', :s].to_a #=> [1, "c", :s]
# File ext/json/lib/json/add/set.rb, line 44 def to_json(*args) as_json.to_json(*args) end
Возвращает строку JSON, представляющую self:
require 'json/add/set' puts Set.new(%w/foo bar baz/).to_json
Вывод:
{"json_class":"Set","a":["foo","bar","baz"]}
static VALUE
set_i_to_set(int argc, VALUE *argv, VALUE set)
{
VALUE klass;
if (argc == 0) {
klass = rb_cSet;
argv = &set;
argc = 1;
}
else {
rb_warn_deprecated("passing arguments to Set#to_set", NULL);
klass = argv[0];
argv[0] = set;
}
if (klass == rb_cSet && rb_obj_is_instance_of(set, rb_cSet) &&
argc == 1 && !rb_block_given_p()) {
return set;
}
return rb_funcall_passing_block(klass, id_new, argc, argv);
} Без аргументов возвращает self (для утиной типизации в методах, принимающих аргументы «множество или объект, преобразуемый в множество»).
Форма с аргументами устарела. Она преобразует множество в другое с помощью klass.new(self, *args, &block).
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.