класс Set
Эта библиотека предоставляет класс Set, который работает с коллекцией неупорядоченных значений без дубликатов. Это гибрид интуитивных возможностей взаимодействия массива и быстрого поиска хэша.
Метод to_set добавлен в Enumerable для удобства.
Set реализует коллекцию неупорядоченных значений без дубликатов. Это гибрид интуитивных возможностей взаимодействия массива и быстрого поиска хэша.
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} например).
Пример
require 'set'
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
Контакты
-
Акинори Муша <knu@iDaemons.org> (текущий основной разработчик)
Что здесь
Сначала, что где-то ещё. Класс Set:
-
Наследует от класса Объект.
-
Включает модуль Enumerable, который предоставляет десятки дополнительных методов.
В частности, класс Set не имеет многих собственных методов для извлечения или итерации. Вместо этого он полагается на методы модуля Enumerable.
Здесь класс Set предоставляет методы, полезные для:
Методы для создания множества
-
::[]: Возвращает новое множество, содержащее заданные объекты. -
::new: Возвращает новое множество, содержащее заданные объекты (если блок не задан) или значения, возвращаемые вызываемым блоком (если блок задан).
Методы для операций с множествами
-
| (алиас
unionи+): Возвращает новое множество, содержащее все элементы изselfи все элементы из заданного перечислимого (без дубликатов). -
& (алиас
intersection): Возвращает новое множество, содержащее все элементы, общие дляselfи заданного перечислимого. -
- (алиас
difference): Возвращает копиюselfсо всеми элементами из заданного перечислимого, удаленными. -
^: Возвращает новое множество, содержащее все элементы из
selfи заданного перечислимого, за исключением общих для обоих.
Методы для сравнения
-
<=>: Возвращает -1, 0 или 1 в зависимости от того,
selfменьше, равно или больше заданного объекта. -
==: Возвращает, равны ли
selfи заданный перечислимый, как определяется методомObject#eql?. -
compare_by_identity?: Возвращает, учитывает ли множество только идентичность при сравнении элементов.
Методы для запросов
-
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: Сбрасывает внутреннее состояние; полезно, если объект был изменён во время работы с элементом в наборе.
Методы публичного класса
# File lib/set.rb, line 230 def self.[](*ary) new(ary) end
Создаёт новый набор, содержащий заданные объекты.
Set[1, 2] # => #<Set: {1, 2}>
Set[1, 2, 1] # => #<Set: {1, 2}>
Set[1, 'c', :s] # => #<Set: {1, "c", :s}>
# File lib/set.rb, line 245
def initialize(enum = nil, &block) # :yields: o
@hash ||= Hash.new(false)
enum.nil? and return
if block
do_with_enum(enum) { |o| add(block[o]) }
else
merge(enum)
end
end Создаёт новый набор, содержащий элементы заданного объекта перечисления.
Если задан блок, элементы 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}>
Общедоступные методы экземпляров
# File lib/set.rb, line 648
def &(enum)
n = self.class.new
if enum.is_a?(Set)
if enum.size > size
each { |o| n.add(o) if enum.include?(o) }
else
enum.each { |o| n.add(o) if include?(o) }
end
else
do_with_enum(enum) { |o| n.add(o) if include?(o) }
end
n
end Возвращает новый набор, содержащий элементы, общие для набора и заданного перечисляемого объекта.
Set[1, 3, 5] & Set[3, 2, 1] #=> #<Set: {3, 1}>
Set['a', 'b', 'z'] & ['a', 'b', 'c'] #=> #<Set: {"a", "b"}>
# File lib/set.rb, line 638 def -(enum) dup.subtract(enum) end
Возвращает новый набор, созданный путем дублирования набора, удаляя каждый элемент, который появляется в заданном перечисляемом объекте.
Set[1, 3, 5] - Set[1, 5] #=> #<Set: {3}>
Set['a', 'b', 'z'] - ['a', 'c'] #=> #<Set: {"b", "z"}>
# File lib/set.rb, line 463 def <=>(set) return unless set.is_a?(Set) case size <=> set.size when -1 then -1 if proper_subset?(set) when +1 then +1 if proper_superset?(set) else 0 if self.==(set) end end
Возвращает 0, если множества равны, -1 / +1, если множество является собственным подмножеством/надмножеством заданного множества, или nil, если оба содержат уникальные элементы.
# File lib/set.rb, line 682
def ==(other)
if self.equal?(other)
true
elsif other.instance_of?(self.class)
@hash == other.instance_variable_get(:@hash)
elsif other.is_a?(Set) && self.size == other.size
other.all? { |o| @hash.include?(o) }
else
false
end
end Возвращает true, если два множества равны. Равенство каждой пары элементов определяется в соответствии с Object#eql?.
Set[1, 2] == Set[2, 1] #=> true Set[1, 3, 5] == Set[1, 5] #=> false Set['a', 'b', 'c'] == Set['a', 'c', 'b'] #=> true Set['a', 'b', 'c'] == ['a', 'c', 'b'] #=> false
Возвращает true, если заданный объект является членом множества, и false в противном случае.
Используется в операторах case:
require 'set' case :apple when Set[:potato, :carrot] "vegetable" when Set[:apple, :banana] "fruit" end # => "fruit"
Или самостоятельно:
Set[1, 2, 3] === 2 #=> true Set[1, 2, 3] === 4 #=> false
# File lib/set.rb, line 669
def ^(enum)
n = Set.new(enum)
each { |o| n.add(o) unless n.delete?(o) }
n
end Возвращает новый набор, содержащий элементы, исключительные между набором и заданным перечисляемым объектом. (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"}>
# File lib/set.rb, line 521 def add(o) @hash[o] = true self end
Добавляет заданный объект в набор и возвращает self. Используйте 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}>
# File lib/set.rb, line 533 def add?(o) add(o) unless include?(o) end
Добавляет заданный объект в набор и возвращает 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 lib/set.rb, line 751
def classify # :yields: o
block_given? or return enum_for(__method__) { size }
h = {}
each { |i|
(h[yield(i)] ||= self.class.new).add(i)
}
h
end Классифицирует множество по возвращаемому значению заданного блока и возвращает словарь пар {значение => множество элементов}. Блок вызывается один раз для каждого элемента множества, передавая элемент в качестве параметра.
require 'set'
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"}>}
Возвращает перечислитель, если блок не задан.
# File lib/set.rb, line 326 def clear @hash.clear self end
Удаляет все элементы и возвращает self.
set = Set[1, 'c', :s] #=> #<Set: {1, "c", :s}>
set.clear #=> #<Set: {}>
set #=> #<Set: {}>
# File lib/set.rb, line 574
def collect!
block_given? or return enum_for(__method__) { size }
set = self.class.new
each { |o| set << yield(o) }
replace(set)
end Заменяет элементы значениями, возвращаемыми collect(). Возвращает перечислитель, если блок не задан.
# File lib/set.rb, line 259
def compare_by_identity
if @hash.respond_to?(:compare_by_identity)
@hash.compare_by_identity
self
else
raise NotImplementedError, "#{self.class.name}\##{__method__} is not implemented"
end
end Заставляет множество сравнивать свои элементы по их идентичности и возвращает self. Этот метод может быть не поддерживаемый всеми подклассами Set.
# File lib/set.rb, line 270 def compare_by_identity? @hash.respond_to?(:compare_by_identity?) && @hash.compare_by_identity? end
Возвращает true, если множество будет сравнивать свои элементы по их идентичности. Также см. Set#compare_by_identity.
# File lib/set.rb, line 539 def delete(o) @hash.delete(o) self end
Удаляет заданный объект из множества и возвращает self. Используйте subtract для удаления сразу нескольких элементов.
# File lib/set.rb, line 546 def delete?(o) delete(o) if include?(o) end
Удаляет заданный объект из множества и возвращает self. Если объект не находится в множестве, возвращает nil.
# File lib/set.rb, line 553
def delete_if
block_given? or return enum_for(__method__) { size }
# @hash.delete_if should be faster, but using it breaks the order
# of enumeration in subclasses.
select { |o| yield o }.each { |o| @hash.delete(o) }
self
end Удаляет каждый элемент множества, для которого блок возвращает true, и возвращает self. Возвращает перечислитель, если блок не задан.
# File lib/set.rb, line 502 def disjoint?(set) !intersect?(set) end
Возвращает 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
# File lib/set.rb, line 779
def divide(&func)
func or return enum_for(__method__) { size }
if func.arity == 2
require 'tsort'
class << dig = {} # :nodoc:
include TSort
alias tsort_each_node each_key
def tsort_each_child(node, &block)
fetch(node).each(&block)
end
end
each { |u|
dig[u] = a = []
each{ |v| func.call(u, v) and a << v }
}
set = Set.new()
dig.each_strongly_connected_component { |css|
set.add(self.class.new(css))
}
set
else
Set.new(classify(&func).values)
end
end Делит множество на подмножества в соответствии с общностью, определённой заданным блоком.
Если арность блока равна 2, элементы o1 и o2 являются общими, если block.call(o1, o2) равно true. В противном случае, элементы o1 и o2 являются общими, если block.call(o1) == block.call(o2).
require 'set'
numbers = Set[1, 3, 4, 6, 9, 10, 11]
set = numbers.divide { |i,j| (i - j).abs == 1 }
set #=> #<Set: {#<Set: {1}>,
# #<Set: {11, 9, 10}>,
# #<Set: {3, 4}>,
# #<Set: {6}>}>
Возвращает перечислитель, если блок не задан.
# File lib/set.rb, line 509
def each(&block)
block or return enum_for(__method__) { size }
@hash.each_key(&block)
self
end Вызывает заданный блок один раз для каждого элемента в множестве, передавая элемент в качестве параметра. Возвращает перечислитель, если блок не задан.
# File lib/set.rb, line 317 def empty? @hash.empty? end
Возвращает true, если множество не содержит элементов.
# File lib/set.rb, line 387 def flatten self.class.new.flatten_merge(self) end
Возвращает новое множество, которое является копией множества, рекурсивно сплющивая каждое содержащее множество.
# File lib/set.rb, line 393
def flatten!
replace(flatten()) if any? { |e| e.is_a?(Set) }
end Эквивалентно Set#flatten, но заменяет получателя результатом на месте. Возвращает nil, если не было внесено изменений.
# File lib/set.rb, line 403 def include?(o) @hash[o] end
Возвращает true, если множество содержит данный объект.
Обратите внимание, что include? и member? не проверяют равенство элементов с использованием ==, как и другие Enumerables.
См. также Enumerable#include?
# File lib/set.rb, line 707
def reset
if @hash.respond_to?(:rehash)
@hash.rehash # This should perform frozenness check.
else
raise FrozenError, "can't modify frozen #{self.class.name}" if frozen?
end
self
end Сбрасывает внутреннее состояние после изменения существующих элементов и возвращает self.
Элементы будут переиндексированы и дедуплицированы.
# File lib/set.rb, line 593
def select!(&block)
block or return enum_for(__method__) { size }
n = size
keep_if(&block)
self if size != n
end Эквивалентно Set#keep_if, но возвращает nil, если изменений не было. Возвращает перечислитель, если блок не задан.
# File lib/set.rb, line 311 def size @hash.size end
Возвращает количество элементов.
# File lib/set.rb, line 435
def subset?(set)
case
when set.instance_of?(self.class) && @hash.respond_to?(:<=)
@hash <= set.instance_variable_get(:@hash)
when set.is_a?(Set)
size <= set.size && all? { |o| set.include?(o) }
else
raise ArgumentError, "value must be a set"
end
end Возвращает true, если множество является подмножеством данного множества.
# File lib/set.rb, line 617
def subtract(enum)
do_with_enum(enum) { |o| delete(o) }
self
end Удаляет каждый элемент, который появляется в заданном перечислимом объекте, и возвращает self.
# File lib/set.rb, line 409
def superset?(set)
case
when set.instance_of?(self.class) && @hash.respond_to?(:>=)
@hash >= set.instance_variable_get(:@hash)
when set.is_a?(Set)
size >= set.size && set.all? { |o| include?(o) }
else
raise ArgumentError, "value must be a set"
end
end Возвращает true, если множество является надмножеством данного множества.
# File lib/set.rb, line 352 def to_a @hash.keys end
Преобразует множество в массив. Порядок элементов не определён.
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 25 def to_json(*args) as_json.to_json(*args) end
Возвращает значение JSON.
# File lib/set.rb, line 361 def to_set(klass = Set, *args, &block) return self if instance_of?(Set) && klass == Set && block.nil? && args.empty? klass.new(self, *args, &block) end
Возвращает self, если аргументы не заданы. В противном случае преобразует множество в другое с klass.new(self, *args, &block).
В подклассах, возвращает klass.new(self, *args, &block), если не переопределено.
# File lib/set.rb, line 627 def |(enum) dup.merge(enum) end
Возвращает новое множество, созданное путём объединения исходного множества и элементов заданного перечислимого объекта.
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}>
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.