# Haikyo's solution

## to Custom Set in the Lua Track

Published at Jul 20 2018 · 0 comments
Instructions
Test suite
Solution

Create a custom set type.

Sometimes it is necessary to define a custom data structure of some type, like a set. In this exercise you will define your own set. How it works internally doesn't matter, as long as it behaves like a set of unique elements.

## Running the tests

To run the tests, run the command busted from within the exercise directory.

## Further information

For more detailed information about the Lua track, including how to get help if you're having trouble, please visit the exercism.io Lua language page.

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### custom-set_spec.lua

local Set = require('custom-set')

describe('custom-set', function()
describe('is_empty', function()
it('should indicate that an empty set is empty', function()
assert.is_true(Set():is_empty())
end)

it('should indicate that sets with elemnts are non-empty', function()
assert.is_false(Set(1):is_empty())
end)
end)

describe('contains', function()
it('should indicate that nothing is an element of an empty set', function()
assert.is_false(Set():contains(1))
end)

it('should indicate that an element is contained in a set that contains the element', function()
assert.is_true(Set(1, 2, 3):contains(1))
assert.is_true(Set(1, 2, 3):contains(2))
assert.is_true(Set(1, 2, 3):contains(3))
end)

it('should indicate that an element that is not in a set is not contained in the set', function()
assert.is_false(Set(1, 2, 3):contains(4))
end)
end)

describe('is_subset', function()
it('should indicate that an empty set is a subset of another empty set', function()
assert.is_true(Set():is_subset(Set()))
end)

it('should indicate that an empty set is a subset of a non-empty set', function()
assert.is_true(Set():is_subset(Set(1)))
end)

it('should indicate that a non-empty set is not a subset of an empty set', function()
assert.is_false(Set(1):is_subset(Set()))
end)

it('should indicate that a non-empty set is a subset of itself', function()
assert.is_true(Set(1, 2, 3):is_subset(Set(1, 2, 3)))
end)

it('should indicate that a proper subset is a subset', function()
assert.is_true(Set(1, 2, 3):is_subset(Set(4, 1, 2, 3)))
end)

it('should indicate that a set is not a subset of another set with different elements but the same element count', function()
assert.is_false(Set(1, 2, 3):is_subset(Set(4, 1, 3)))
end)
end)

describe('is_disjoint', function()
it('should indicate that the empty set is disjoint with itself', function()
assert.is_true(Set():is_disjoint(Set()))
end)

it('should indicate that the empty set is disjoint with a non-empty set', function()
assert.is_true(Set():is_disjoint(Set(1)))
end)

it('should indicate that a non-empty set is not disjoint with an empty set', function()
assert.is_true(Set(1):is_disjoint(Set()))
end)

it('should indicate that sets with an element in common are not disjoint', function()
assert.is_false(Set(1, 2):is_disjoint(Set(2, 3)))
end)

it('should indicate that sets with no elements in common are disjoint', function()
assert.is_true(Set(1, 2):is_disjoint(Set(3, 4)))
end)
end)

describe('equality', function()
it('should consider empty sets equal', function()
assert.is_true(Set():equals(Set()))
end)

it('should not consider an empty set to be equal to a non-empty set', function()
assert.is_false(Set():equals(Set(1, 2, 3)))
end)

it('should not consider a non-empty set to be equal to an empty set', function()
assert.is_false(Set(1, 2, 3):equals(Set()))
end)

it('should ignore order', function()
assert.is_true(Set(1, 3):equals(Set(3, 1)))
end)

it('should consider different sets to be different', function()
assert.is_false(Set(1, 2, 3):equals(Set(1, 2, 4)))
end)
end)

it('should allow an element to be added to an empty set', function()
local s = Set()
assert.is_true(s:contains(3))
end)

it('should allow an element to be added to a non-empty set', function()
local s = Set(1, 2, 4)
assert.is_true(s:equals(Set(1, 2, 3, 4)))
end)

it('should allow an element to be re-added to a set', function()
local s = Set(1, 2, 3)
assert.is_true(s:equals(Set(1, 2, 3)))
end)
end)

describe('intersection', function()
it('should give the empty set as the intersection of two empty sets', function()
assert.is_true(Set():intersection(Set()):equals(Set()))
end)

it('should intersect an empty set with a non-empty set', function()
assert.is_true(Set():intersection(Set(3, 2, 5)):equals(Set()))
end)

it('should intersect a non-empty set with an empty set', function()
assert.is_true(Set(1, 2, 3, 4):intersection(Set()):equals(Set()))
end)

it('should intersect a single element set with itself', function()
assert.is_true(Set(3):intersection(Set(3)):equals(Set(3)))
end)

it('should intersect sets with a single element in common', function()
assert.is_true(Set(1, 2, 3):intersection(Set(3, 4, 5)):equals(Set(3)))
end)

it('should intersect sets with a multiple elements in common', function()
assert.is_true(Set(1, 2, 3, 4):intersection(Set(3, 2, 5)):equals(Set(2, 3)))
end)

it('should intersect a set with a subset', function()
assert.is_true(Set(1, 2, 3):intersection(Set(2, 3)):equals(Set(2, 3)))
end)

it('should intersect sets with no elements in common', function()
assert.is_true(Set(1, 2, 3):intersection(Set(4, 5, 6)):equals(Set()))
end)
end)

describe('intersection', function()
it('should give the empty set as the intersection of two empty sets', function()
assert.is_true(Set():intersection(Set()):equals(Set()))
end)

it('should intersect an empty set with a non-empty set', function()
assert.is_true(Set():intersection(Set(3, 2, 5)):equals(Set()))
end)

it('should intersect a non-empty set with an empty set', function()
assert.is_true(Set(1, 2, 3, 4):intersection(Set()):equals(Set()))
end)

it('should intersect a single element set with itself', function()
assert.is_true(Set(3):intersection(Set(3)):equals(Set(3)))
end)

it('should intersect sets with a single element in common', function()
assert.is_true(Set(1, 2, 3):intersection(Set(3, 4, 5)):equals(Set(3)))
end)

it('should intersect sets with a multiple elements in common', function()
assert.is_true(Set(1, 2, 3, 4):intersection(Set(3, 2, 5)):equals(Set(2, 3)))
end)

it('should intersect a set with a subset', function()
assert.is_true(Set(1, 2, 3):intersection(Set(2, 3)):equals(Set(2, 3)))
end)

it('should intersect sets with no elements in common', function()
assert.is_true(Set(1, 2, 3):intersection(Set(4, 5, 6)):equals(Set()))
end)
end)

describe('difference', function()
it('should give the difference of two empty sets as the empty set', function()
assert.is_true(Set():difference(Set()):equals(Set()))
end)

it('should give the difference of an empty set and a non-empty set as the empty set', function()
assert.is_true(Set():difference(Set(3, 2, 5)):equals(Set()))
end)

it('should give the difference of a non-empty set and the empty set as the non-empty set', function()
assert.is_true(Set(1, 2, 3, 4):difference(Set()):equals(Set(1, 2, 3, 4)))
end)

it('should give the difference of two sets with an intersection', function()
assert.is_true(Set(3, 2, 1):difference(Set(2, 4)):equals(Set(1, 3)))
end)
end)

describe('union', function()
it('should produce the empty set as the union of two empty sets', function()
assert.is_true(Set():union(Set()):equals(Set()))
end)

it('should give the union of an empty set with another set as the other set', function()
assert.is_true(Set():union(Set(2)):equals(Set(2)))
end)

it('should give the union of a non-empty set and an empty set as the non-empty set', function()
assert.is_true(Set(1, 3):union(Set()):equals(Set(1, 3)))
end)

it('should produce the union of different sets', function()
assert.is_true(Set(1, 3):union(Set(2, 3)):equals(Set(1, 2, 3)))
end)
end)
end)
local Set = {}

function Set:new(...)
local s = {}
s.data = {...}
table.sort(s.data)
setmetatable(s, self)
self.__index = self
return s
end

function Set:is_empty()
return #self.data == 0
end

function Set:contains(v)
for i = 0, #self.data do
if self.data[i] == v then return true end
end
return false
end

for _, v in pairs({...}) do
if not self:contains(v) then
table.insert(self.data, v)
end
end
table.sort(self.data)
return self
end

function Set:is_subset(s)
return table.concat(s.data, '.'):find(table.concat(self.data, '.')) ~= nil
end

function Set:is_disjoint(s)
if self:is_empty() or s:is_empty() then
return true
end
for _, v in pairs(self.data) do
if s:contains(v) then
return false
end
end
return true
end

function Set:equals(s)
return table.concat(self.data, '.') == table.concat(s.data, '.')
end

function Set:intersection(s)
local intersection = Set:new()
for _, v in pairs(self.data) do
if s:contains(v) then
end
end
return intersection
end

function Set:difference(s)
local difference = Set:new()
for _, v in pairs(self.data) do
if not s:contains(v) then
end
end
return difference
end

function Set:union(s)
local union = Set:new(table.unpack(self.data))
for _, v in pairs(s.data) do
if not union:contains(v) then
end
end
return union
end

local function set(...)
return Set:new(...)
end

return set