Модуль:Set

Материал из свободной русской энциклопедии «Традиция»
Перейти к: навигация, поиск

Before: {

   elements =   {
       [1] = true,
       [2] = true,
       [3] = true,
       [4] = true
   },
   no_elements =  4

} After: {

   elements =   {
       [1] = true,
       [2] = true,
       [4] = true,
       one =  true,
       four =  true,
       two =  true
   },
   no_elements =  6

}


-- Множества:
-- Функции: add (), remove (), count (), is_empty (), any () и contains ().
-- Перегруженные операторы: + (объединение), - (разность), * (прямое произведение), () (итератор).

-- Dependencies:
local Class = (require 'Module:Class' or require 'Class.lua').create
local serialise = (require 'Module:Test' or require 'Test.lua').serialise

local Set = Class {
	-- Число элементов:
	no_elements	= 0
	-- Элементы:
  , elements	= {}	
}		-- local Set = Class {...}

-- Конструктор:
function Set:_init (...)
	local args = {...}
	if #args == 1 and type (args [1]) == 'table' then 
		for _, element in ipairs (args [1]) do
			self:add (element)
		end
	else
		for _, element in ipairs (args) do
			self:add (element)
		end
	end
end		-- function Set:_init (elements)

-- Методы:
function Set:add (element)
	if not self.elements [element] and element then
		self.elements [element] = true
		self.no_elements = self.no_elements + 1
		return true
	else
		return false
	end
end		-- function Set:append (element)

function Set:remove (element)
	if self.elements [element] then	
		self.elements [element] = nil
		self.no_elements = self.no_elements - 1
		return true
	else
		return false
	end
end		-- function Set:remove (element)

function Set:count ()
	return self.no_elements
end		-- function Set:count ()

function Set:is_empty ()
	return self.no_elements == 0
end		-- function Set:_is_empty ()

function Set:any ()
	for element, _ in pairs (self.elements) do
		return element
	end
end		-- function Set:any ()

function Set:contains (element)
	return self.elements [element]
end		-- function Set:contains (element)

-- Итератор:
-- Обходит даже вновь добавленные элементы.
function Set:_call ()
	local coroutine = coroutine	
	return coroutine.wrap (function ()
		local iterated = Set ()
		while not (self - iterated):is_empty () do
			for item, _ in pairs (self.elements) do
				if not iterated:contains (item) then
					iterated:add (item)
					coroutine.yield (item)
				end
			end
		end
	end)	-- return coroutine.wrap (function () ...
end		-- function Set:_call ()

-- Объединение:
function Set:__add (set)
	local sum = mw.clone (self)
	if type (set) == 'table' and set.is_a and set:is_a (Set) then
		-- Ради производительности, не будем использовать итератор:
		for element, _ in pairs (set.elements) do
			sum:add (element)
		end
	else
		sum:add (set)
	end
	return sum
end	--	function Set:__add (set)

-- Разность множеств:
function Set:__sub (subtrahend)
	if type (subtrahend) == 'table' and subtrahend.is_a and subtrahend:is_a (Set) then
		local diff = Set ()
		-- Здесь нельзя использовать итератор, так как он вызывает этот же метод:
		for element, _ in pairs (self.elements) do
			if not subtrahend:contains (element) then
				diff:add (element)
			end
		end
		return diff
	else
		return mw.clone (self):remove (subtrahend)
	end
end	--	function Set:__sub (subtrahend)

-- Декартово произведение:
function Set:__mul (set)
	local product = Set ()
	-- Ради производительности, не используем здесь итератор:
	for element1, _ in pairs (self) do
		for element2, __ in pairs (set) do
			product:add {element1, element2}
		end
	end
	return product
end		-- function Set:__mul (set)

-- Для тестирования:
function Set:test ()
	local s = Set (1, 2, 3, 4)
	local ret = 'Before: ' .. serialise (s)
	for element in s () do
		if element == 1 then
			s:add 'one'
		elseif element == 2 then
			s:add 'two'
		elseif element == 3 then
			s:remove (element)
		elseif element == 4 then
			s:add 'four'
		end
	end
	ret = ret .. '\nAfter: ' .. serialise (s)
	return ret
end		-- function Set:test ()

return Set