Documentation
¶
Overview ¶
Package set provides a generic Set data structure for storing unique elements.
Set is a collection that contains no duplicate elements. It models the mathematical set abstraction and provides operations for testing membership, computing unions, intersections, and differences.
Basic Usage ¶
Create and use a set:
s := set.New[string]()
s.Add("apple")
s.Add("banana")
s.Add("apple") // Duplicate, not added
fmt.Println(s.Size()) // 2
fmt.Println(s.Contains("apple")) // true
Create from a slice:
numbers := []int{1, 2, 3, 2, 1}
s := set.FromSlice(numbers)
fmt.Println(s.Size()) // 3 (duplicates removed)
Adding and Removing ¶
s := set.New[int]() added := s.Add(1) // true (new element) added = s.Add(1) // false (duplicate) count := s.AddAll(2, 3, 4, 3) // Adds 3 new elements fmt.Println(count) // 3 removed := s.Remove(2) // true removed = s.Remove(99) // false (not present)
Membership Testing ¶
s := set.New[string]()
s.Add("hello")
if s.Contains("hello") {
fmt.Println("Found!")
}
if s.IsEmpty() {
fmt.Println("Set is empty")
}
size := s.Size()
Set Operations ¶
**Union** - All elements from both sets:
s1 := set.FromSlice([]int{1, 2, 3})
s2 := set.FromSlice([]int{3, 4, 5})
union := s1.Union(s2)
fmt.Println(union.ToSlice()) // [1, 2, 3, 4, 5]
**Intersection** - Elements in both sets:
intersection := s1.Intersection(s2) fmt.Println(intersection.ToSlice()) // [3]
**Difference** - Elements in first set but not second:
diff := s1.Difference(s2) fmt.Println(diff.ToSlice()) // [1, 2]
**Symmetric Difference** - Elements in either set but not both:
symDiff := s1.SymmetricDifference(s2) fmt.Println(symDiff.ToSlice()) // [1, 2, 4, 5]
Subset and Superset ¶
s1 := set.FromSlice([]int{1, 2})
s2 := set.FromSlice([]int{1, 2, 3, 4})
if s1.IsSubset(s2) {
fmt.Println("s1 is a subset of s2")
}
if s2.IsSuperset(s1) {
fmt.Println("s2 is a superset of s1")
}
Equality ¶
s1 := set.FromSlice([]int{1, 2, 3})
s2 := set.FromSlice([]int{3, 2, 1})
if s1.Equal(s2) {
fmt.Println("Sets are equal") // Order doesn't matter
}
Iteration ¶
s := set.FromSlice([]string{"a", "b", "c"})
s.Range(func(item string) bool {
fmt.Println(item)
return true // Continue iteration
})
slice := s.ToSlice() // Convert to slice
Copying Sets ¶
original := set.FromSlice([]int{1, 2, 3})
copy := original.Clone()
copy.Add(4)
fmt.Println(original.Size()) // 3 (unchanged)
fmt.Println(copy.Size()) // 4
You can also copy by assignment since Set uses value semantics:
s1 := set.New[int]() s1.Add(1) s2 := s1 // Both reference the same underlying map s2.Add(2) fmt.Println(s1.Size()) // 2 (same map)
Use Cases ¶
**Removing Duplicates:**
data := []int{1, 2, 2, 3, 3, 3, 4}
unique := set.FromSlice(data).ToSlice()
**Tracking Seen Items:**
seen := set.New[string]()
for _, item := range items {
if seen.Contains(item) {
fmt.Println("Duplicate:", item)
continue
}
seen.Add(item)
process(item)
}
**Set Algebra:**
admins := set.FromSlice([]string{"alice", "bob"})
users := set.FromSlice([]string{"bob", "charlie"})
allPeople := admins.Union(users)
bothRoles := admins.Intersection(users)
adminOnly := admins.Difference(users)
**Tag Filtering:**
required := set.FromSlice([]string{"go", "backend"})
articleTags := set.FromSlice([]string{"go", "backend", "tutorial"})
if required.IsSubset(articleTags) {
fmt.Println("Article matches all required tags")
}
Performance ¶
**Time Complexity:**
- Add: O(1) average
- Remove: O(1) average
- Contains: O(1) average
- Size/IsEmpty: O(1)
- Union/Intersection/Difference: O(n+m)
- IsSubset/IsSuperset: O(n)
- Equal: O(n)
**Space Complexity:**
- O(n) where n is the number of elements
- Uses map[T]struct{} for zero-byte values
Value Semantics ¶
Set uses value semantics (not pointer receivers). This is safe and efficient because:
- The underlying map is a reference type
- Copying a Set copies only the map header (~24 bytes), not the data
- Multiple Set values can share the same underlying map data
For independent sets, use Clone():
s1 := set.New[int]() s2 := s1.Clone() // Independent copy
Comparison with map[T]struct{} ¶
// Manual set with map
m := make(map[string]struct{})
m["item"] = struct{}{}
_, exists := m["item"]
// Set package
s := set.New[string]()
s.Add("item")
exists := s.Contains("item")
Set provides:
- Cleaner API
- Set operations (union, intersection, etc.)
- Convenience methods
- Clear intent in code
Thread Safety ¶
Set is not thread-safe. For concurrent access, use external synchronization:
var mu sync.RWMutex s := set.New[int]() mu.Lock() s.Add(1) mu.Unlock() mu.RLock() exists := s.Contains(1) mu.RUnlock()
Index ¶
- type Set
- func (s *Set[T]) Add(item T) bool
- func (s *Set[T]) AddAll(items ...T) int
- func (s Set[T]) AsMap() map[T]struct{}
- func (s *Set[T]) Clear()
- func (s *Set[T]) Clone() Set[T]
- func (s *Set[T]) Contains(item T) bool
- func (s *Set[T]) Difference(other Set[T]) Set[T]
- func (s *Set[T]) Equal(other Set[T]) bool
- func (s *Set[T]) Intersection(other Set[T]) Set[T]
- func (s *Set[T]) IsEmpty() bool
- func (s *Set[T]) IsSubset(other Set[T]) bool
- func (s *Set[T]) IsSuperset(other Set[T]) bool
- func (s *Set[T]) Range(fn func(T) bool)
- func (s *Set[T]) Remove(item T) bool
- func (s Set[T]) Seq() iter.Seq[T]
- func (s *Set[T]) Size() int
- func (s *Set[T]) String() string
- func (s *Set[T]) SymmetricDifference(other Set[T]) Set[T]
- func (s *Set[T]) ToSlice() []T
- func (s *Set[T]) Union(other Set[T]) Set[T]
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Set ¶
type Set[T comparable] struct { // contains filtered or unexported fields }
Set is a collection of unique comparable elements. It is safe to copy Set values as the underlying map is a reference type.
func FromSlice ¶
func FromSlice[T comparable](slice []T) Set[T]
FromSlice creates a new Set containing all unique elements from the given slice.
func (*Set[T]) Add ¶
Add inserts an element into the set. Returns true if the element was added (wasn't already present), false otherwise.
func (*Set[T]) AddAll ¶
AddAll inserts multiple elements into the set. Returns the count of elements that were actually added (excludes duplicates).
func (Set[T]) AsMap ¶
func (s Set[T]) AsMap() map[T]struct{}
AsMap returns the underlying map representation of the Set. The returned map has keys of type T and values of empty struct{}. Useful for interoperability with code that expects map[T]struct{}.
WARNING: This returns a reference to the internal map, NOT a copy. Modifying the returned map will affect the Set. Use Clone() if you need an independent copy.
func (*Set[T]) Clone ¶
Clone creates a deep copy of the Set with an independent internal map. Modifications to the clone will not affect the original Set and vice versa.
func (*Set[T]) Difference ¶
Difference returns a new set containing elements in this set but not in the other set.
func (*Set[T]) Intersection ¶
Intersection returns a new set containing only elements present in both sets.
func (*Set[T]) IsSuperset ¶
IsSuperset returns true if this set contains all elements of the other set.
func (*Set[T]) Range ¶
Range calls the given function for each element in the set. If the function returns false, iteration stops.
func (*Set[T]) Remove ¶
Remove deletes an element from the set. Returns true if the element was removed (was present), false otherwise.
func (Set[T]) Seq ¶
Seq returns an iter.Seq that yields all elements in the set. This enables use with Go 1.23 for-range loops.
func (*Set[T]) SymmetricDifference ¶
SymmetricDifference returns a new set containing elements in either set but not in both.