(self | other) - (self & other)
end
end
x = [1, 2, 3, 4, 5]
y = [3, 4, 5, 6, 7]
z = x ^ y # [1, 2, 6, 7]
Чтобы проверить, входит ли некий элемент в множество, пользуйтесь методом include?
или member?
(синоним, подмешанный из модуля Comparable
):
x = [1, 2, 3]
if x.include? 2
puts 'yes' # Печатается 'yes'
else
puts 'no'
end
Конечно, это некоторое отступление от канонов математики, где для обозначения принадлежности множеству применяется символ, похожий на греческую букву эпсилон. Отступление в том смысле, что множество находится слева, а не справа от оператора, то есть мы спрашиваем не «принадлежит ли данный элемент множеству», а «содержит ли множество данный элемент».
Многим это безразлично. Но привыкшие к языку Pascal или Python (или впитавшие математический формализм с молоком матери) хотели бы, чтобы было по-другому. Такую возможность мы реализуем в следующем фрагменте:
class Object
def in(other)
other.include? self
end
end
x = [1, 2, 3]
if 2.in x
puts 'yes' # Печатается 'yes'
else
puts 'no'
end
Лично я отправил запрос на изменение Ruby (RCR 241) с предложением ввести в язык оператор in
. Он должен походить на одноименный оператор в языках Pascal, Python и даже SQL.
У этой идеи есть свои достоинства (к тому же in
— уже зарезервированное слово), но единодушного одобрения она не получила. Может быть, оператор in появится в Ruby, а может, и нет.
Теперь обратимся к подмножествам и надмножествам. Как определить, является ли данное множество подмножеством или надмножеством другого? Встроенных методов для этого нет, но мы можем поступить следующим образом:
class Array
def subset?(other)
self.each do |x|
if !(other.include? x)
return false
end
end
true
end
def superset?(other)
other.subset?(self)
end
end
a = [1, 2, 3, 4]
b = [2, 3]
с = [2, 3, 4, 5]
flag1 = c.subset? a # false
flag2 = b.subset? a # true
flag3 = c.superset? b # true
Обратите внимание: мы выбрали «естественный» порядок, то есть задаем вопрос x.subset? у
— «является ли x
подмножеством у?
», а не наоборот.
Для распознавания пустого множества достаточно проверить, пуст ли массив. Это делает метод empty?
.
Операция дополнения опирается на идею универсального множества. Однако «универсальное множество» в каждой конкретной ситуации определяется по-разному, поэтому лучшим решением будет самое простое: сначала определим, что такое универсальное множество, а потом вычислим разность.
universe = [1, 2, 3, 4, 5, 6]
а = [2, 3]
b = universe - а # Дополнение а = [1, 4, 5, 6]
Если считаете необходимым, можете определить и унарный оператор (например, -
или ~
для выполнения этой операции.
Элементы множества можно перебирать, обходя массив. Единственная разница заключается в том, что элементы будут появляться в определенном порядке, а это может оказаться нежелательным. О том, как перебирать массив в случайном порядке, будет рассказано в разделе 8.1.18.
Наконец, иногда возникает необходимость вычислить степень множества. Это не что иное, как множество всех подмножеств данного множества (включая его само и пустое множество). Читатели, знакомые с дискретной математикой, в особенности с комбинаторикой, понимают, что число таких подмножеств равно 2n. Сгенерировать степень множества можно следующим образом:
class Array
def powerset
num = 2**size
ps = Array.new(num, [])
self.each_index do |i|
a = 2**i
b = 2**(i+1) — 1
j = 0
while j < num-1
for j in j+a..j+b
ps[j] += [self[i]]
end