-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
565 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# sets | ||
|
||
support`interface{}`/`any` which implement Comparator interface and builtin type. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
package sets | ||
|
||
// Set sets.Set is a set of interface, | ||
// implemented via map[T]struct{} for minimal memory consumption. | ||
type Set[T comparable] map[T]struct{} | ||
|
||
// New creates a T from a list of values. | ||
func New[T comparable](items ...T) Set[T] { | ||
ss := Set[T]{} | ||
return ss.Insert(items...) | ||
} | ||
|
||
// NewFrom creates a T from a keys of a map[T](? extends any). | ||
// If the value passed in is not actually a map, this will panic. | ||
func NewFrom[T comparable, V any, M ~map[T]V](m M) Set[T] { | ||
ret := Set[T]{} | ||
for k := range m { | ||
ret[k] = struct{}{} | ||
} | ||
return ret | ||
} | ||
|
||
// Insert adds items to the set. | ||
func (s Set[T]) Insert(items ...T) Set[T] { | ||
for _, item := range items { | ||
s[item] = struct{}{} | ||
} | ||
return s | ||
} | ||
|
||
// Delete removes all items from the set. | ||
func (s Set[T]) Delete(items ...T) Set[T] { | ||
for _, item := range items { | ||
delete(s, item) | ||
} | ||
return s | ||
} | ||
|
||
// Contains returns true if and only if item is contained in the set. | ||
func (s Set[T]) Contains(item T) bool { | ||
_, contained := s[item] | ||
return contained | ||
} | ||
|
||
// ContainsAll returns true if and only if all items are contained in the set. | ||
func (s Set[T]) ContainsAll(items ...T) bool { | ||
for _, item := range items { | ||
if !s.Contains(item) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// ContainsAny returns true if any items are contained in the set. | ||
func (s Set[T]) ContainsAny(items ...T) bool { | ||
for _, item := range items { | ||
if s.Contains(item) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// Difference returns a set of objects that are not in s2 | ||
// For example: | ||
// s1 = {a1, a2, a3} | ||
// s2 = {a1, a2, a4, a5} | ||
// s1.Difference(s2) = {a3} | ||
// s2.Difference(s1) = {a4, a5}. | ||
func (s Set[T]) Difference(s2 Set[T]) Set[T] { | ||
result := New[T]() | ||
for key := range s { | ||
if !s2.Contains(key) { | ||
result[key] = struct{}{} | ||
} | ||
} | ||
return result | ||
} | ||
|
||
// Union returns a new set which includes items in either s1 or s2. | ||
// For example: | ||
// s1 = {a1, a2} | ||
// s2 = {a3, a4} | ||
// s1.Union(s2) = {a1, a2, a3, a4} | ||
// s2.Union(s1) = {a1, a2, a3, a4}. | ||
func (s Set[T]) Union(s2 Set[T]) Set[T] { | ||
result := New[T]() | ||
for key := range s { | ||
result[key] = struct{}{} | ||
} | ||
for key := range s2 { | ||
result[key] = struct{}{} | ||
} | ||
return result | ||
} | ||
|
||
// Intersection returns a new set which includes the item in BOTH s1 and s2 | ||
// For example: | ||
// s1 = {a1, a2} | ||
// s2 = {a2, a3} | ||
// s1.Intersection(s2) = {a2}. | ||
func (s Set[T]) Intersection(s2 Set[T]) Set[T] { | ||
var walk, other Set[T] | ||
result := New[T]() | ||
if s.Len() < s2.Len() { | ||
walk = s | ||
other = s2 | ||
} else { | ||
walk = s2 | ||
other = s | ||
} | ||
for key := range walk { | ||
if other.Contains(key) { | ||
result[key] = struct{}{} | ||
} | ||
} | ||
return result | ||
} | ||
|
||
// Merge is like Union, however it modifies the current set it's applied on | ||
// with the given s2 set. | ||
// For example: | ||
// s1 = {a1, a2} | ||
// s2 = {a3, a4} | ||
// s1.Merge(s2), s1 = {a1, a2, a3, a4} | ||
// s2.Merge(s1), s2 = {a1, a2, a3, a4}. | ||
func (s Set[T]) Merge(s2 Set[T]) Set[T] { | ||
for item := range s2 { | ||
s[item] = struct{}{} | ||
} | ||
return s | ||
} | ||
|
||
// IsSuperset returns true if and only if s1 is a superset of s2. | ||
func (s Set[T]) IsSuperset(s2 Set[T]) bool { | ||
for item := range s2 { | ||
if !s.Contains(item) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// IsSubset returns true if and only if s1 is a superset of s2. | ||
func (s Set[T]) IsSubset(s2 Set[T]) bool { | ||
for item := range s { | ||
if !s2.Contains(item) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// List returns the contents as a sorted slice. | ||
func (s Set[T]) List() []T { | ||
res := make([]T, 0, len(s)) | ||
for key := range s { | ||
res = append(res, key) | ||
} | ||
return res | ||
} | ||
|
||
// Equal returns true if and only if s1 is equal (as a set) to s2. | ||
// Two sets are equal if their membership is identical. | ||
// (In practice, this means same elements, order doesn't matter). | ||
func (s Set[T]) Equal(s2 Set[T]) bool { | ||
return len(s) == len(s2) && s.IsSuperset(s2) | ||
} | ||
|
||
// Pop Returns a single element from the set. | ||
func (s Set[T]) Pop() (v T, ok bool) { | ||
for key := range s { | ||
delete(s, key) | ||
return key, true | ||
} | ||
return | ||
} | ||
|
||
// Len returns the size of the set. | ||
func (s Set[T]) Len() int { | ||
return len(s) | ||
} | ||
|
||
// Each traverses the items in the Set, calling the provided function for each | ||
// set member. Traversal will continue until all items in the Set have been | ||
// visited, or if the closure returns false. | ||
func (s Set[T]) Each(f func(item T) bool) { | ||
for item := range s { | ||
if !f(item) { | ||
break | ||
} | ||
} | ||
} | ||
|
||
// Clone returns a new Set with a copy of s. | ||
func (s Set[T]) Clone() Set[T] { | ||
ns := New[T]() | ||
s.Each(func(item T) bool { | ||
ns[item] = struct{}{} | ||
return true | ||
}) | ||
return ns | ||
} |
Oops, something went wrong.