Skip to content

Instantly share code, notes, and snippets.

@CosmicToast
Last active January 2, 2024 19:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CosmicToast/7bbcf0cfb8ae93c9f6717eb1ef8481c0 to your computer and use it in GitHub Desktop.
Save CosmicToast/7bbcf0cfb8ae93c9f6717eb1ef8481c0 to your computer and use it in GitHub Desktop.
go-collect
package collect
// Set represents a generic set of comparable elements.
type Set[T comparable] map[T]struct{}
// Has checks whether the set holds a given value.
func (s Set[T]) Has(v T) bool {
_, ok := s[v]
return ok
}
// Add adds values to the set. You may add as many as you wish.
func (s Set[T]) Add(vs ...T) {
for _, v := range vs {
s[v] = struct{}{}
}
}
// Remove removes values from the set. You may remove as many as you wish.
func (s Set[T]) Remove(vs ...T) {
for _, v := range vs {
delete(s, v)
}
}
// Clear reinitializes the set.
func (s *Set[T]) Clear() {
(*s) = NewSet[T]()
}
// Items returns a slice of all elements currently in the set.
// Note that unless you actually want a collection, you should call Iter or
// Filter instead. Items calls Iter internally.
func (s Set[T]) Items() []T {
out := make([]T, 0, len(s))
for v := range s.Iter() {
out = append(out, v)
}
return out
}
func fromChan[T comparable](cs ...chan T) Set[T] {
out := NewSet[T]()
for _, c := range cs {
for v := range c {
out.Add(v)
}
}
return out
}
// Difference returns a new set that holds the elements present in the receiver, but not s2.
func (s Set[T]) Difference(s2 Set[T]) Set[T] {
return fromChan(s.Filter(func(v T)bool {
return !s2.Has(v)
}))
}
// Intersection returns a new set that holds elements present in both sets.
func (s Set[T]) Intersection(s2 Set[T]) Set[T] {
return fromChan(s.Filter(func(v T)bool {
return s2.Has(v)
}))
}
// Union returns a new set that holds the elements of both sets.
func (s Set[T]) Union(s2 Set[T]) Set[T] {
return fromChan(s.Iter(), s2.Iter())
}
// Size returns how many elements are in the set.
func (s Set[T]) Size() int {
return len(s)
}
// NewSet initializes a set of a given type.
// Note that if you pass any initial values, the type will be inferred.
func NewSet[T comparable](vs ...T) Set[T] {
var out Set[T] = make(map[T]struct{})
out.Add(vs...)
return out
}
func (s Set[T]) iter(c chan T, filter func(T)bool) {
for k := range s {
if filter(k) {
c <- k
}
}
close(c)
}
// Iter allows you to iterate over the set.
// It is efficient even for very large sets.
func (s Set[T]) Iter() chan T {
out := make(chan T)
go s.iter(out, func(_ T)bool { return true })
return out
}
// Filter is like Iter, but you only get elements that pass the filter function.
// It is efficient even for very large sets.
func (s Set[T]) Filter(filter func(T)bool) chan T {
out := make(chan T)
go s.iter(out, filter)
return out
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment