Skip to content

Commit

Permalink
Merge pull request JuliaLang#30 from SaschaMann/smann/ex-custom-set
Browse files Browse the repository at this point in the history
Add exercise: custom set
  • Loading branch information
SaschaMann authored Feb 8, 2017
2 parents f476a02 + 1d4f2b6 commit 1806de8
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 0 deletions.
13 changes: 13 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,19 @@
"filtering",
"mathematics"
]
},
{
"slug": "custom-set",
"difficulty": 5,
"topics": [
"types",
"parametric types",
"methods",
"multiple dispatch",
"function extension",
"mathematics",
"iterators"
]
}
],
"deprecated": [
Expand Down
1 change: 1 addition & 0 deletions exercises/custom-set/HINTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The tests require a constructor that takes an array. The internals of your custom set implementation can use other data structures but you may have to implement an outer constructor that takes exactly one array for the tests to pass.
Empty file.
51 changes: 51 additions & 0 deletions exercises/custom-set/example.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Base: AbstractSet, isempty, length, in, issubset, start, next, done,
push!, ==, copy, intersect!, intersect, union!, union

type CustomSet{T} <: AbstractSet
elements::Array{T, 1}
end

isempty(s::CustomSet) = isempty(s.elements)
length(s::CustomSet) = length(s.elements)
in(element, s::CustomSet) = in(element, s.elements) # this also defines issubset(::CustomSet, ::CustomSet)
==(s1::CustomSet, s2::CustomSet) = issubset(s1, s2) && issubset(s2, s1)
copy(s::CustomSet) = CustomSet(copy(s.elements))
push!(s::CustomSet, element) = push!(s.elements, element)

# Iterator protocol
start(::CustomSet) = 1
next(s::CustomSet, state) = s.elements[state], state + 1
done(s::CustomSet, state) = state > length(s)

function disjoint(s1::CustomSet, s2::CustomSet)
for element in s1
element in s2 && return false
end
return true
end

function complement!(s1::CustomSet, s2::CustomSet)
for (i, element) in enumerate(s1)
element in s2 && deleteat!(s1.elements, i)
end
return s1
end
complement(s1::CustomSet, s2::CustomSet) = complement!(copy(s1), s2)

function intersect!(s1::CustomSet, s2::CustomSet)
tbd = Int[]
for (i, element) in enumerate(s1)
element in s2 || push!(tbd, i)
end
deleteat!(s1.elements, tbd)
return s1
end
intersect(s1::CustomSet, s2::CustomSet) = intersect!(copy(s1), s2)

function union!(s1::CustomSet, s2::CustomSet)
for element in s2
element in s1 || push!(s1, element)
end
return s1
end
union(s1::CustomSet, s2::CustomSet) = union!(copy(s1), s2)
200 changes: 200 additions & 0 deletions exercises/custom-set/runtests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
using Base.Test

include("custom-set.jl")

# canonical data
@testset "empty" begin
@test isempty(CustomSet([]))
@test !isempty(CustomSet([1]))
end

@testset "in (contains)" begin
@test !(1 in CustomSet([]))
@test 1 in CustomSet([1, 2, 3])
@test !(4 in CustomSet([1, 2, 3]))
end

@testset "subset" begin # TODO ⊆, ⊈
@test issubset(CustomSet([]), CustomSet([]))
@test issubset(CustomSet([]), CustomSet([1]))
@test !issubset(CustomSet([1]), CustomSet([]))
@test issubset(CustomSet([1, 2, 3]), CustomSet([1, 2, 3]))
@test issubset(CustomSet([1, 2, 3]), CustomSet([4, 1, 2, 3]))
@test !issubset(CustomSet([1, 2, 3]), CustomSet([4, 1, 3]))
end

@testset "disjoint" begin
@test disjoint(CustomSet([]), CustomSet([]))
@test disjoint(CustomSet([]), CustomSet([1]))
@test disjoint(CustomSet([1]), CustomSet([]))
@test !disjoint(CustomSet([1, 2]), CustomSet([2, 3]))
@test disjoint(CustomSet([1, 2]), CustomSet([3, 4]))
end

@testset "equal" begin
@test CustomSet([]) == CustomSet([])
@test CustomSet([]) != CustomSet([1, 2, 3])
@test CustomSet([1, 2, 3]) != CustomSet([])
@test CustomSet([1, 2]) == CustomSet([2, 1])
@test CustomSet([1, 2, 3]) != CustomSet([1, 2, 4])
end

@testset "add" begin
@test begin
custom_set = CustomSet([])
push!(custom_set, 3)
custom_set == CustomSet([3])
end
@test begin
custom_set = CustomSet([1, 2, 4])
push!(custom_set, 3)
custom_set == CustomSet([1, 2, 3, 4])
end
@test begin
custom_set = CustomSet([1, 2, 3])
push!(custom_set, 3)
custom_set == CustomSet([1, 2, 3])
end
end

@testset "intersection" begin
@testset "in-place" begin
@test begin
cs1 = CustomSet([])
cs2 = CustomSet([])
intersect!(cs1, cs2)
isempty(cs1)
end
@test begin
cs1 = CustomSet([])
cs2 = CustomSet([3, 2, 5])
intersect!(cs1, cs2)
isempty(cs1)
end
@test begin
cs1 = CustomSet([1, 2, 3, 4])
cs2 = CustomSet([])
intersect!(cs1, cs2)
isempty(cs1)
end
@test begin
cs1 = CustomSet([1, 2, 3])
cs2 = CustomSet([4, 5, 6])
intersect!(cs1, cs2)
isempty(cs1)
end
@test begin
cs1 = CustomSet([1, 2, 3, 4])
cs2 = CustomSet([3, 2, 5])
intersect!(cs1, cs2)
cs1 == CustomSet([2, 3])
end
end
@testset "not in-place" begin # TODO use operator ∩
@test isempty(intersect(CustomSet([]), CustomSet([])))
@test isempty(intersect(CustomSet([]), CustomSet([3, 2, 5])))
@test isempty(intersect(CustomSet([1, 2, 3, 4]), CustomSet([])))
@test isempty(intersect(CustomSet([1, 2, 3]), CustomSet([4, 5, 6])))
@test intersect(CustomSet([1, 2, 3, 4]), CustomSet([3, 2, 5])) == CustomSet([2, 3])
end
end

@testset "complement (difference)" begin
@testset "in-place" begin
@test begin
cs1 = CustomSet([])
cs2 = CustomSet([])
complement!(cs1, cs2)
isempty(cs1)
end
@test begin
cs1 = CustomSet([])
cs2 = CustomSet([3, 2, 5])
complement!(cs1, cs2)
isempty(cs1)
end
@test begin
cs1 = CustomSet([1, 2, 3, 4])
cs2 = CustomSet([])
complement!(cs1, cs2)
cs1 == CustomSet([1, 2, 3, 4])
end
@test begin
cs1 = CustomSet([3, 2, 1])
cs2 = CustomSet([2, 4])
complement!(cs1, cs2)
cs1 == CustomSet([1, 3])
end
end
@testset "not in-place" begin
@test isempty(complement(CustomSet([]), CustomSet([])))
@test isempty(complement(CustomSet([]), CustomSet([3, 2, 5])))
@test complement(CustomSet([1, 2, 3, 4]), CustomSet([])) == CustomSet([1, 2, 3, 4])
@test complement(CustomSet([3, 2, 1]), CustomSet([2, 4])) == CustomSet([1, 3])
end
end

@testset "union" begin
@testset "in-place" begin
@test begin
cs1 = CustomSet([])
cs2 = CustomSet([])
union!(cs1, cs2)
isempty(cs1)
end
@test begin
cs1 = CustomSet([])
cs2 = CustomSet([2])
union!(cs1, cs2)
cs1 == CustomSet([2])
end
@test begin
cs1 = CustomSet([1, 3])
cs2 = CustomSet([])
union!(cs1, cs2)
cs1 == CustomSet([1, 3])
end
@test begin
cs1 = CustomSet([1, 3])
cs2 = CustomSet([2, 3])
union!(cs1, cs2)
cs1 == CustomSet([3, 2, 1])
end
end
@testset "not in-place" begin
@test isempty(union(CustomSet([]), CustomSet([])))
@test union(CustomSet([]), CustomSet([2])) == CustomSet([2])
@test union(CustomSet([1, 3]), CustomSet([])) == CustomSet([1, 3])
@test union(CustomSet([1, 3]), CustomSet([2, 3])) == CustomSet([3, 2, 1])
end
end

# language specific tests
@testset "implements correct abstract type" begin
@test CustomSet <: Base.AbstractSet
end

@testset "length" begin
@test length(CustomSet([])) == 0
@test length(CustomSet([1, 2, 3])) == 3
end

@testset "iterable" begin
@test begin
cs1 = CustomSet([1, 2, 3, 4])
cs2 = CustomSet([])
for element in cs1
push!(cs2, element)
end
cs1 == cs2
end
end

@testset "copy" begin
@test begin
cs1 = CustomSet([1, 2, 3])
cs2 = copy(cs1)
push!(cs1, 4)
cs2 == CustomSet([1, 2, 3])
end
end

0 comments on commit 1806de8

Please sign in to comment.