# glennj's solution

## to Custom Set in the Lua Track

Published at Mar 11 2019 · 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 = {}
Set.__index = Set
setmetatable(Set, {
__call = function(cls, ...) return cls:new(...) end,
})

-- Set constructor
-- Pass some arguments to populate the set
function Set:new(...)
local set = {}
setmetatable(set, self)
return set
end

-- add some elements to the set
for i = 1, select('#', ...) do
local element = select(i, ...)
self[element] = true
end
end

-- return the set's elements as a list
function Set:elements()
local elements = {}
for elem in pairs(self) do
elements[#elements+1] = elem
end
return elements
end

-- add all of another set's elements to myself
end

-- my size
function Set:size()
local count = 0
for _ in pairs(self) do
count = count + 1
end
return count
end

-- true if I have no elements
function Set:is_empty()
return not next(self)
end

-- true if I contain the given element
function Set:contains(element)
return not not self[element]
end

-- true if I am a subset of other
-- (I have no elements that other does not have)
function Set:is_subset(other)
for elem in pairs(self) do
if not other:contains(elem) then
return false
end
end
return true
end

-- true if other has none of my elements
function Set:is_disjoint(other)
for elem in pairs(self) do
if other:contains(elem) then
return false
end
end
return true
end

-- sets are subsets of each other (same size, same elements)
function Set:equals(other)
return self:is_subset(other) and other:is_subset(self)
end

-- return a set containing the elements common to both sets
function Set:intersection(other)
local int = Set:new()
for elem in pairs(self) do
if other:contains(elem) then
end
end
return int
end

-- return a set containing elements in my set and not in other
function Set:difference(other)
local diff = Set:new()
for elem in pairs(self) do
if not other:contains(elem) then
end
end
return diff
end

-- return a set containing all elements of both sets
function Set:union(other)
local union = Set:new()
return union
end

return Set``````