Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module set

go 1.12

require (
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f
github.com/jtolds/gls v4.2.1+incompatible
github.com/smartystreets/assertions v0.0.0-20180301161246-7678a5452ebe
github.com/smartystreets/goconvey v0.0.0-20170602164621-9e8dc3f972df
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smartystreets/assertions v0.0.0-20180301161246-7678a5452ebe h1:N9Tx6rKITAMSw2lgWIyLOgoTikD33tNWmiT7GPkz0es=
github.com/smartystreets/assertions v0.0.0-20180301161246-7678a5452ebe/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20170602164621-9e8dc3f972df h1:AawEzDdiSpy07QO9efSOHQ/BRincGLxilju4pOq3k8s=
github.com/smartystreets/goconvey v0.0.0-20170602164621-9e8dc3f972df/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
82 changes: 82 additions & 0 deletions linkedhashsetint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package set

// LinkedHashSetINT linked hash set implementation using linkedHashMap as its
// underlying data structure.
//
// - Does not allow storing duplicated values
// - Does not allow storing nil values
// - Maintains insertion order over iteration
type LinkedHashSetINT struct {
linkedHashMap *linkedHashMap
}

// Add adds elements to the linked hash set
func (l *LinkedHashSetINT) Add(elements ...int) {
for _, element := range elements {
l.linkedHashMap.Put(element, nil)
}
}

// Remove removes elements from the linked hash set
func (l *LinkedHashSetINT) Remove(elements ...int) {
for _, element := range elements {
l.linkedHashMap.Remove(element)
}
}

// Iter iterates over each element of the linked hash set
func (l *LinkedHashSetINT) Iter() <-chan int {
ch := make(chan int, l.Length())
go func() {
for element := range l.linkedHashMap.Iter() {
ch <- element.key.(int)
}
close(ch)
}()
return ch
}

// Length returns the length of the linked hash set
func (l *LinkedHashSetINT) Length() int {
return l.linkedHashMap.Length()
}

// AsSlice returns a slice of all values of the linked hash set
func (l *LinkedHashSetINT) AsSlice() []int {
values := make([]int, 0, l.Length())
for value := range l.Iter() {
values = append(values, value)
}
return values
}

// AsInterface returns a slice of all values of the linked hash set
// as interface{}
func (l *LinkedHashSetINT) AsInterface() []interface{} {
values := make([]interface{}, 0, l.Length())
for value := range l.Iter() {
values = append(values, value)
}
return values
}

// InArray returns whether the given item is in array or not
func (l *LinkedHashSetINT) InArray(search int) bool {
for item := range l.Iter() {
if item == search {
return true
}
}
return false
}

// NewLinkedHashSetINT returns a new LinkedHashSetINT with the provided items
func NewLinkedHashSetINT(ints ...int) *LinkedHashSetINT {
lhm := &LinkedHashSetINT{
linkedHashMap: newLinkedHashMap(),
}
if len(ints) > 0 {
lhm.Add(ints...)
}
return lhm
}
162 changes: 162 additions & 0 deletions linkedhashsetint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package set

import (
"testing"

. "github.com/smartystreets/goconvey/convey"
)

var giantINTSlice = make([]int, giantSliceLength)

func init() {
for i := 0; i < giantSliceLength; i++ {
giantINTSlice[i] = int(i + 1)
}
}

func TestLinkedHashSetINTAdd(t *testing.T) {
Convey("Given LinkedHashSetINT.Add", t, func() {
Convey("It should not store elements that are already on the Set", func() {
set := NewLinkedHashSetINT()
set.Add(0, 0)
set.Add(0)
So(set.Length(), ShouldEqual, 1)
})
Convey("It should store elements with the correct constraints", func() {
set := NewLinkedHashSetINT()
set.Add(0, 1, 2, 99, 93, 32, 00, 01, 2)
So(set.Length(), ShouldEqual, 6)
})
})
}

func TestLinkedHashSetINTRemove(t *testing.T) {
Convey("Given LinkedHashSetINT.Remove", t, func() {
Convey("When a big list is given", func() {
set := NewLinkedHashSetINT()
set.Add(giantINTSlice...)
Convey("It should remove elements from a Set", func() {
// first element
set.Remove(giantINTSlice[0])
set.Remove(giantINTSlice[0])
set.Remove(giantINTSlice[0])
set.Remove(giantINTSlice[0])
// last element
set.Remove(giantINTSlice[len(giantINTSlice)-1])
// arbitrary elements
set.Remove(giantINTSlice[1000], giantINTSlice[2000], giantINTSlice[3000])
So(set.Length(), ShouldEqual, len(giantINTSlice)-5)
})
})
Convey("When list with one item is given", func() {
set := NewLinkedHashSetINT()
set.Add(1)
Convey("It should remove the element from the set", func() {
set.Remove(1)
So(set.Length(), ShouldEqual, 0)
})
})
})
}

func TestLinkedHashSetINTIter(t *testing.T) {
Convey("Given LinkedHashSetINT.Iter", t, func() {
Convey("It should iterate over all elements of the set respecting the insertion order", func() {
set := NewLinkedHashSetINT()
set.Add(giantINTSlice...)
var (
i int
somethingWentWrong bool
)
for value := range set.Iter() {
if value != giantINTSlice[i] {
somethingWentWrong = true
break
}
i++
}
So(somethingWentWrong, ShouldBeFalse)
So(i, ShouldEqual, giantSliceLength)
})
})
}

func TestLinkedHashSetINTLength(t *testing.T) {
Convey("Given LinkedHashSetINT.Length", t, func() {
Convey("It should return the correct length of the Set", func() {
set := NewLinkedHashSetINT()
set.Add(0, 1, 2, 99, 93, 32, 00, 01, 2)
So(set.Length(), ShouldEqual, 6)
set.Remove(1)
So(set.Length(), ShouldEqual, 5)
set.Remove(2, 99, 94)
So(set.Length(), ShouldEqual, 3)
set.Add(94)
So(set.Length(), ShouldEqual, 4)
})

Convey("It should return the correct length of the Set no matter the length of the Set", func() {
set := NewLinkedHashSetINT()
set.Add(giantINTSlice...)
So(set.Length(), ShouldEqual, len(giantINTSlice))
})
})
}

func TestIntInArray(t *testing.T) {
Convey("Given LinkedHashSetINT.InArray", t, func() {
Convey("When the element is in the list", func() {
set := NewLinkedHashSetINT(2, 4, 6, 8)
So(set.InArray(2), ShouldBeTrue)
So(set.InArray(4), ShouldBeTrue)
So(set.InArray(6), ShouldBeTrue)
So(set.InArray(8), ShouldBeTrue)
})
Convey("When the element is not in the list", func() {
set := NewLinkedHashSetINT(2, 4, 6, 8)
So(set.InArray(1), ShouldBeFalse)
So(set.InArray(3), ShouldBeFalse)
So(set.InArray(5), ShouldBeFalse)
So(set.InArray(7), ShouldBeFalse)
})
Convey("When the list is empty", func() {
set := NewLinkedHashSetINT()
So(set.InArray(1), ShouldBeFalse)
So(set.InArray(3), ShouldBeFalse)
So(set.InArray(5), ShouldBeFalse)
So(set.InArray(7), ShouldBeFalse)
})
})
}

func TestIntAsSlice(t *testing.T) {
Convey("Given LinkedHashSetINT.AsSlice", t, func() {
Convey("It should return the correct slice", func() {
expectedArray := []int{2, 4, 6, 8}
set := NewLinkedHashSetINT(expectedArray...)

array := set.AsSlice()
So(array, ShouldHaveLength, len(expectedArray))

for i, value := range array {
So(value, ShouldEqual, expectedArray[i])
}
})
})
}

func TestIntAsInterface(t *testing.T) {
Convey("Given LinkedHashSetINT.AsInterface", t, func() {
Convey("It should return the correct slice", func() {
expectedArray := []int{2, 4, 6, 8}
set := NewLinkedHashSetINT(expectedArray...)

array := set.AsInterface()
So(array, ShouldHaveLength, len(expectedArray))

for i, value := range array {
So(value.(int), ShouldEqual, expectedArray[i])
}
})
})
}