Last active
January 2, 2024 19:00
-
-
Save CosmicToast/7bbcf0cfb8ae93c9f6717eb1ef8481c0 to your computer and use it in GitHub Desktop.
go-collect
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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