adding set interface and threadsafe implementation
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package simpleset
|
||||
|
||||
import "maps"
|
||||
|
||||
type Set[T comparable] struct {
|
||||
contents map[T]struct{}
|
||||
}
|
||||
|
||||
func New[T comparable](elements ...T) *Set[T] {
|
||||
s := &Set[T]{
|
||||
contents: make(map[T]struct{}),
|
||||
}
|
||||
for _, e := range elements {
|
||||
s.Add(e)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Set[T]) Add(element T) {
|
||||
s.contents[element] = struct{}{}
|
||||
}
|
||||
|
||||
func (s *Set[T]) Remove(element T) {
|
||||
delete(s.contents, element)
|
||||
}
|
||||
|
||||
func (s *Set[T]) Contains(element T) bool {
|
||||
_, exists := s.contents[element]
|
||||
return exists
|
||||
}
|
||||
|
||||
func (s *Set[T]) Size() int {
|
||||
return len(s.contents)
|
||||
}
|
||||
|
||||
func (s *Set[T]) ToSlice() []T {
|
||||
elements := make([]T, 0, len(s.contents))
|
||||
for e := range s.contents {
|
||||
elements = append(elements, e)
|
||||
}
|
||||
return elements
|
||||
}
|
||||
|
||||
func (s *Set[T]) Equal(other *Set[T]) bool {
|
||||
return maps.Equal(s.contents, other.contents)
|
||||
}
|
||||
|
||||
func (s *Set[T]) Union(other *Set[T]) *Set[T] {
|
||||
result := New[T]()
|
||||
for e := range s.contents {
|
||||
result.Add(e)
|
||||
}
|
||||
for e := range other.contents {
|
||||
result.Add(e)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *Set[T]) Intersection(other *Set[T]) *Set[T] {
|
||||
result := New[T]()
|
||||
for e := range s.contents {
|
||||
if other.Contains(e) {
|
||||
result.Add(e)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *Set[T]) Difference(other *Set[T]) *Set[T] {
|
||||
result := New[T]()
|
||||
for e := range s.contents {
|
||||
if !other.Contains(e) {
|
||||
result.Add(e)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package simpleset
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIntersection(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3, 4)
|
||||
s2 := New[int](3, 4, 5, 6)
|
||||
want := New[int](3, 4)
|
||||
got := s1.Intersection(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Intersection() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntersection_Empty(t *testing.T) {
|
||||
s1 := New[int](1, 2)
|
||||
s2 := New[int](3, 4)
|
||||
want := New[int]()
|
||||
got := s1.Intersection(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Intersection() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntersection_Identical(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3)
|
||||
s2 := New[int](1, 2, 3)
|
||||
want := New[int](1, 2, 3)
|
||||
got := s1.Intersection(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Intersection() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntersection_Subset(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3, 4, 5)
|
||||
s2 := New[int](2, 3)
|
||||
want := New[int](2, 3)
|
||||
got := s1.Intersection(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Intersection() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntersection_EmptySet(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3)
|
||||
s2 := New[int]()
|
||||
want := New[int]()
|
||||
got := s1.Intersection(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Intersection() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntersection_BothEmpty(t *testing.T) {
|
||||
s1 := New[int]()
|
||||
s2 := New[int]()
|
||||
want := New[int]()
|
||||
got := s1.Intersection(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Intersection() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifference(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3, 4)
|
||||
s2 := New[int](3, 4, 5, 6)
|
||||
want := New[int](1, 2)
|
||||
got := s1.Difference(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Difference() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifference_Empty(t *testing.T) {
|
||||
s1 := New[int](1, 2)
|
||||
s2 := New[int](1, 2)
|
||||
want := New[int]()
|
||||
got := s1.Difference(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Difference() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifference_Subset(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3, 4, 5)
|
||||
s2 := New[int](2, 3)
|
||||
want := New[int](1, 4, 5)
|
||||
got := s1.Difference(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Difference() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifference_EmptySet(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3)
|
||||
s2 := New[int]()
|
||||
want := New[int](1, 2, 3)
|
||||
got := s1.Difference(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Difference() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifference_BothEmpty(t *testing.T) {
|
||||
s1 := New[int]()
|
||||
s2 := New[int]()
|
||||
want := New[int]()
|
||||
got := s1.Difference(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Difference() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnion(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3)
|
||||
s2 := New[int](3, 4, 5)
|
||||
want := New[int](1, 2, 3, 4, 5)
|
||||
got := s1.Union(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Union() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnion_EmptySet(t *testing.T) {
|
||||
s1 := New[int](1, 2, 3)
|
||||
s2 := New[int]()
|
||||
want := New[int](1, 2, 3)
|
||||
got := s1.Union(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Union() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnion_BothEmpty(t *testing.T) {
|
||||
s1 := New[int]()
|
||||
s2 := New[int]()
|
||||
want := New[int]()
|
||||
got := s1.Union(s2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Union() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
want := New[int](1, 2, 3)
|
||||
got := New[int]()
|
||||
got.Add(1)
|
||||
got.Add(2)
|
||||
got.Add(3)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Add() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemov(t *testing.T) {
|
||||
want := New[int](1, 3)
|
||||
got := New[int](1, 2, 3)
|
||||
got.Remove(2)
|
||||
if !got.Equal(want) {
|
||||
t.Errorf("Remove() = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
func TestContains(t *testing.T) {
|
||||
s := New[int](1, 2, 3)
|
||||
if !s.Contains(2) {
|
||||
t.Errorf("Contains(2) = false; want true")
|
||||
}
|
||||
if s.Contains(4) {
|
||||
t.Errorf("Contains(4) = true; want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
s := New[int](1, 2, 3, 4)
|
||||
want := 4
|
||||
got := s.Size()
|
||||
if got != want {
|
||||
t.Errorf("Size() = %d; want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToSlice(t *testing.T) {
|
||||
s := New[int](1, 2, 3)
|
||||
want := []int{1, 2, 3}
|
||||
got := s.ToSlice()
|
||||
mapping := make(map[int]bool)
|
||||
for _, v := range got {
|
||||
mapping[v] = true
|
||||
}
|
||||
for _, v := range want {
|
||||
if !mapping[v] {
|
||||
t.Errorf("ToSlice() missing element %d; got %v", v, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user