diff --git a/datastructure/set.go b/datastructure/set.go new file mode 100644 index 0000000..57b1299 --- /dev/null +++ b/datastructure/set.go @@ -0,0 +1,105 @@ +package datastructure + +// Set is a data container, like slice, but element of set is not duplicate +type Set[T comparable] map[T]bool + +// NewSet return a instance of set +func NewSet[T comparable](values ...T) Set[T] { + set := make(Set[T]) + set.Add(values...) + return set +} + +// Add value to set +func (s Set[T]) Add(values ...T) { + for _, v := range values { + s[v] = true + } +} + +// Contain checks if set contains value or not +func (s Set[T]) Contain(value T) bool { + _, ok := s[value] + return ok +} + +// Contain checks if set contains other set +func (s Set[T]) ContainAll(other Set[T]) bool { + for k := range other { + _, ok := s[k] + if !ok { + return false + } + } + return true +} + +// Clone return a copy of set +func (s Set[T]) Clone() Set[T] { + set := NewSet[T]() + set.Add(s.Values()...) + return set +} + +// Delete value of set +func (s Set[T]) Delete(values ...T) { + for _, v := range values { + delete(s, v) + } +} + +// Equal checks if two set has same elements or not +func (s Set[T]) Equal(other Set[T]) bool { + if s.Size() != other.Size() { + return false + } + + return s.ContainAll(other) && other.ContainAll(s) +} + +// Iterate call function by every element of set +func (s Set[T]) Iterate(fn func(value T)) { + for v := range s { + fn(v) + } +} + +// IsEmpty checks the set is empty or not +func (s Set[T]) IsEmpty() bool { + return len(s) == 0 +} + +// Size get the number of elements in set +func (s Set[T]) Size() int { + return len(s) +} + +// Values return all values of set +func (s Set[T]) Values() []T { + values := make([]T, 0, 0) + + s.Iterate(func(value T) { + values = append(values, value) + }) + + return values +} + +// Union creates a new set contain all element of set s and other +func (s Set[T]) Union(other Set[T]) Set[T] { + set := s.Clone() + set.Add(other.Values()...) + return set +} + +// Intersection creates a new set whose element both be contained in set s and other +func (s Set[T]) Intersection(other Set[T]) Set[T] { + set := NewSet[T]() + s.Iterate(func(value T) { + if other.Contain(value) { + set.Add(value) + } + }) + + return set +} diff --git a/datastructure/set_test.go b/datastructure/set_test.go new file mode 100644 index 0000000..45acca2 --- /dev/null +++ b/datastructure/set_test.go @@ -0,0 +1,129 @@ +package datastructure + +import ( + "testing" + + "github.com/duke-git/lancet/internal" +) + +func TestSet_Add(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Add") + + set := NewSet[int]() + set.Add(1, 2, 3) + + expected := NewSet(1, 2, 3) + + assert.Equal(true, set.Equal(expected)) +} + +func TestSet_Contain(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Contain") + + set := NewSet[int]() + set.Add(1, 2, 3) + + assert.Equal(true, set.Contain(1)) + assert.Equal(false, set.Contain(4)) +} + +func TestSet_ContainAll(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_ContainAll") + + set1 := NewSet(1, 2, 3) + set2 := NewSet(1, 2) + set3 := NewSet(1, 2, 3, 4) + + assert.Equal(true, set1.ContainAll(set2)) + assert.Equal(false, set1.ContainAll(set3)) +} + +func TestSet_Clone(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Clone") + + set1 := NewSet(1, 2, 3) + set2 := set1.Clone() + + assert.Equal(true, set1.Size() == set2.Size()) + assert.Equal(true, set1.ContainAll(set2)) +} + +func TestSet_Delete(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Delete") + + set := NewSet[int]() + set.Add(1, 2, 3) + set.Delete(3) + + expected := NewSet(1, 2) + + assert.Equal(true, set.Equal(expected)) +} + +func TestSet_Equal(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Equal") + + set1 := NewSet(1, 2, 3) + set2 := NewSet(1, 2, 3) + set3 := NewSet(1, 2, 3, 4) + + assert.Equal(true, set1.Equal(set2)) + assert.Equal(false, set1.Equal(set3)) +} + +func TestSet_Iterate(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Iterate") + + set := NewSet(1, 2, 3) + arr := []int{} + set.Iterate(func(value int) { + arr = append(arr, value) + }) + + assert.Equal(3, len(arr)) +} + +func TestSet_IsEmpty(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_IsEmpty") + + set := NewSet[int]() + assert.Equal(true, set.IsEmpty()) +} + +func TestSet_Size(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Size") + + set := NewSet(1, 2, 3) + assert.Equal(3, set.Size()) +} + +func TestSet_Values(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Values") + + set := NewSet(1, 2, 3) + values := set.Values() + + assert.Equal(3, len(values)) +} + +func TestSet_Union(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Union") + + set1 := NewSet(1, 2, 3) + set2 := NewSet(2, 3, 4, 5) + expected := NewSet(1, 2, 3, 4, 5) + unionSet := set1.Union(set2) + + assert.Equal(expected, unionSet) +} + +func TestSet_Intersection(t *testing.T) { + assert := internal.NewAssert(t, "TestSet_Intersection") + + set1 := NewSet(1, 2, 3) + set2 := NewSet(2, 3, 4, 5) + expected := NewSet(2, 3) + intersectionSet := set1.Intersection(set2) + + assert.Equal(expected, intersectionSet) +}