2023-08-25 14:36:38 +02:00
|
|
|
package obiutils
|
|
|
|
|
|
2026-11-03 20:55:35 +11:00
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"reflect"
|
|
|
|
|
"slices"
|
|
|
|
|
)
|
2023-08-25 14:36:38 +02:00
|
|
|
|
|
|
|
|
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...)
|
2023-08-25 14:36:38 +02:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2026-11-03 20:55:35 +11:00
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-25 14:36:38 +02:00
|
|
|
// String returns a string representation of the set.
|
|
|
|
|
//
|
2026-11-03 20:55:35 +11:00
|
|
|
// 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.
|
2023-08-25 14:36:38 +02:00
|
|
|
func (s Set[E]) String() string {
|
2026-11-03 20:55:35 +11:00
|
|
|
members := s.Members()
|
|
|
|
|
slices.SortFunc(members, func(a, b E) int { return compareMembers(a, b) })
|
|
|
|
|
return fmt.Sprintf("%v", members)
|
2023-08-25 14:36:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
}
|