Files
obitools4/pkg/obiutils/set.go
T

134 lines
3.5 KiB
Go
Raw Normal View History

package obiutils
import (
"fmt"
"reflect"
"slices"
)
type Set[E comparable] map[E]struct{}
// MakeSet creates a new Set with the provided values.
//
// The function takes a variadic parameter `vals` of type `E` which represents the values
// that will be added to the Set.
//
// The function returns a Set of type `Set[E]` which contains the provided values.
func MakeSet[E comparable](vals ...E) Set[E] {
s := Set[E]{}
for _, v := range vals {
s[v] = struct{}{}
}
return s
}
// NewSet creates a new Set with the given values.
//
// It takes a variadic parameter of type E, where E is a comparable type.
// It returns a pointer to a Set of type E.
func NewSet[E comparable](vals ...E) *Set[E] {
2025-02-27 10:19:39 +01:00
s := MakeSet(vals...)
return &s
}
// Add adds the given values to the set.
//
// It takes a variadic parameter `vals` of type `E`.
// There is no return type for this function.
func (s Set[E]) Add(vals ...E) {
for _, v := range vals {
s[v] = struct{}{}
}
}
// Contains checks if the set contains a given element.
//
// Parameters:
// - v: the element to check for presence in the set.
//
// Returns:
// - bool: true if the set contains the given element, false otherwise.
func (s Set[E]) Contains(v E) bool {
_, ok := s[v]
return ok
}
// Members returns a slice of all the elements in the set.
//
// It does not modify the original set.
// It returns a slice of type []E.
func (s Set[E]) Members() []E {
result := make([]E, 0, len(s))
for v := range s {
result = append(result, v)
}
return result
}
// compareMembers orders two set members: numbers by value, strings
// alphabetically, anything else by its printed form. It is only used to give
// the string representation of a set a stable order.
func compareMembers(a, b any) int {
va, vb := reflect.ValueOf(a), reflect.ValueOf(b)
switch {
case va.CanInt() && vb.CanInt():
return cmpOrdered(va.Int(), vb.Int())
case va.CanUint() && vb.CanUint():
return cmpOrdered(va.Uint(), vb.Uint())
case va.CanFloat() && vb.CanFloat():
return cmpOrdered(va.Float(), vb.Float())
case va.Kind() == reflect.String && vb.Kind() == reflect.String:
return cmpOrdered(va.String(), vb.String())
}
return cmpOrdered(fmt.Sprint(a), fmt.Sprint(b))
}
func cmpOrdered[T int64 | uint64 | float64 | string](a, b T) int {
switch {
case a < b:
return -1
case a > b:
return 1
}
return 0
}
// String returns a string representation of the set.
//
// The members are formatted with fmt, in increasing order: a Go map has no
// order, and a representation changing from one call to the next is of no use
// to print, log or compare.
func (s Set[E]) String() string {
members := s.Members()
slices.SortFunc(members, func(a, b E) int { return compareMembers(a, b) })
return fmt.Sprintf("%v", members)
}
// Union returns a new set that is the union of the current set and the specified set.
//
// Parameters:
// - s2: the set to be unioned with the current set.
//
// Return:
// - Set[E]: the resulting set after the union operation.
func (s Set[E]) Union(s2 Set[E]) Set[E] {
result := MakeSet(s.Members()...)
result.Add(s2.Members()...)
return result
}
// Intersection returns a new set that contains the common elements between the current set and another set.
//
// Parameter:
// - s2: the other set to compare with.
// Return:
// - Set[E]: a new set that contains the common elements.
func (s Set[E]) Intersection(s2 Set[E]) Set[E] {
result := MakeSet[E]()
for _, v := range s.Members() {
if s2.Contains(v) {
result.Add(v)
}
}
return result
}