Files
obitools4/pkg/obiutils/set.go
T
Eric Coissac d7d63f315c Refactor primer logic and enhance taxonomy features
This commit introduces refinements to primer design strategies, species identification rules, and performance analysis. It also updates taxonomy handling by implementing methods for setting and dropping taxonomic paths, along with necessary utility improvements for set handling and comprehensive test coverage.
2026-11-03 22:46:34 +11:00

135 lines
3.5 KiB
Go

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] {
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
}