Documentation
¶
Overview ¶
Package set implements a Set using an underlying map as an aliased type.
Additionally the Set implements methods from the python set type including unions, intersections, differences and symmetric differences.
Data can be fed to a set from an array or slice and additionally from an iterator. The implementation avoids allocations where possible.
Unlike python, sets can only consist of comparable types. This eliminates the possibility of a 'set of sets'.
Similarly to map, sets are not goroutine safe.
This is not production code but simply a demonstration of generics and iterators.
[Python Set]: https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset Frozenset is NOT supported although it would be possible.
This implementation using generics has a few problems. Map keys or sets are 'comparable' (obeys the == and != operations) whereas slices are 'cmp.Ordered' (obeys <, <=, ==, >=, > operations) and this introduces some basic incompatibilities. Attempting to sort a set using slices.Sort from the go slices package will not work as this requires the cmp.Ordered constraint.
A better solution is to implement 'set' as a stripped down version of 'map' in the go source code perhaps.
For a deep discussion of generics see the blog by Axel Wagner
https://go.dev/blog/generic-interfaces
It is tempting to change the comparable constraint to a constraint that EITHER requires 'comparable' OR the presence of an Equal method - something like this:
type Comparer[T any] interface {
Equal(T) bool
}
type Comparable[T any] interface {
comparable | Comparer[T]
}
but this will not compile as 'comparable' is disallowed from forming part of a constraint union.
To fix this the various types that make up 'comparable' must be explicitly enumerated in the Comparable type. This is fragile as this may change in subsequent Go versions.
type Comparable[T any] interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string | Comparer[T]
}
and it is unclear how to generalise this to (say) structs and pointers of any type.
Ref: https://github.com/golang/go/issues/51259
Ref: https://go.dev/blog/comparable
An alternative would be to use:
type Comparable[T any] interface {
comparable
Comparer[T]
}
but this makes generic types such as 'string' or 'int' fail because they have no Equal method.
To reiterate the only real solution is to add 'set' as a proper type in the golang source tree.
Index ¶
- func Equal[S Set[T], T comparable](s1 S, s2 S) bool
- type Set
- func (s Set[T]) Add(items ...T)
- func (s Set[T]) Contains(item T) bool
- func (s Set[T]) Difference(other Set[T]) Set[T]
- func (s Set[T]) Equal(other Set[T]) bool
- func (s Set[T]) Intersection(other Set[T]) Set[T]
- func (s Set[T]) IntersectionIter(items iter.Seq[T]) Set[T]
- func (s Set[T]) Iter() iter.Seq[T]
- func (s Set[T]) List() []T
- func (s Set[T]) Remove(items ...T)
- func (s Set[T]) String() string
- func (s Set[T]) Sub(other Set[T]) bool
- func (s Set[T]) SymmetricDifference(other Set[T]) Set[T]
- func (s Set[T]) Union(other Set[T]) Set[T]
- func (s Set[T]) UnionIter(items iter.Seq[T]) Set[T]
Examples ¶
- FromIter
- FromSlice
- FromSlice (Int)
- FromSlice (Struct)
- Set.Add
- Set.Difference
- Set.Equal
- Set.Equal (Not)
- Set.Equal (Wronglength)
- Set.Intersection
- Set.IntersectionIter
- Set.Iter
- Set.List
- Set.Remove
- Set.String
- Set.String (Nil)
- Set.Sub
- Set.Sub (Larger)
- Set.Sub (Not)
- Set.Sub (Smaller)
- Set.SymmetricDifference
- Set.Union
- Set.Union (Int)
- Set.Union (Struct)
- Set.UnionIter
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Equal ¶ added in v1.0.0
func Equal[S Set[T], T comparable](s1 S, s2 S) bool
Equal returns true if two sets contain the same items.
Types ¶
type Set ¶
type Set[T comparable] map[T]struct{}
Set is a synonym of a map with no values.
func FromIter ¶
func FromIter[T comparable](items iter.Seq[T]) Set[T]
FromIter creates a new set from an iterator. This is useful for creating a set from a map.
Example ¶
m := map[string]int{"a": 0, "b": 1}
s := set.FromIter(maps.Keys(m))
fmt.Printf(
"%d %t %t",
len(s),
s.Contains("a"),
s.Contains("b"),
)
Output: 2 true true
func FromSlice ¶
func FromSlice[T comparable](items ...T) Set[T]
FromSlice creates a new set from a slice or array.
Example ¶
a := []string{"a", "b"}
s := set.FromSlice(a...)
fmt.Printf(
"%d %t %t",
len(s),
s.Contains("a"),
s.Contains("b"),
)
Output: 2 true true
Example (Int) ¶
a := []int{1, 2}
s := set.FromSlice(a...)
fmt.Printf(
"%d %t %t",
len(s),
s.Contains(1),
s.Contains(2),
)
Output: 2 true true
Example (Struct) ¶
type testStruct struct {
name string
index int
}
oneTestStruct := testStruct{"one", 1}
twoTestStruct := testStruct{"two", 2}
a := []testStruct{oneTestStruct, twoTestStruct}
s := set.FromSlice(a...)
fmt.Printf(
"%d %t %t",
len(s),
s.Contains(oneTestStruct),
s.Contains(twoTestStruct),
)
Output: 2 true true
func (Set[T]) Add ¶
func (s Set[T]) Add(items ...T)
Add adds one or more items to set.
Example ¶
s := set.FromSlice("a")
s.Add("b", "c")
fmt.Printf(
"%d %t %t %t",
len(s),
s.Contains("a"),
s.Contains("b"),
s.Contains("c"),
)
Output: 3 true true true
func (Set[T]) Difference ¶
Difference returns set that consists of items that are in first set and not in second set.
Example ¶
a := []string{"a", "b", "c"}
m := []string{"c", "d", "e"}
s := set.FromSlice(a...)
t := set.FromSlice(m...)
u := s.Difference(t)
fmt.Printf(
"%d %t %t %t %t %t",
len(u),
u.Contains("a"),
u.Contains("b"),
u.Contains("c"),
u.Contains("d"),
u.Contains("e"),
)
Output: 2 true true false false false
func (Set[T]) Equal ¶ added in v1.0.0
Equal returns true if sets are equal.
Example ¶
a := []int{1, 2}
b := []int{1, 2}
s := set.FromSlice(a...)
t := set.FromSlice(b...)
fmt.Printf(
"%t",
s.Equal(t),
)
Output: true
Example (Not) ¶
a := []int{1, 2}
b := []int{1, 3}
s := set.FromSlice(a...)
t := set.FromSlice(b...)
fmt.Printf(
"%t",
s.Equal(t),
)
Output: false
Example (Wronglength) ¶
a := []int{1, 2}
b := []int{1, 2, 3}
s := set.FromSlice(a...)
t := set.FromSlice(b...)
fmt.Printf(
"%t",
s.Equal(t),
)
Output: false
func (Set[T]) Intersection ¶
Intersection returns set that consists of items that are in both sets.
Example ¶
a := []string{"a", "b", "c"}
m := []string{"c", "d", "e"}
s := set.FromSlice(a...)
t := set.FromSlice(m...)
u := s.Intersection(t)
fmt.Printf("%v", u)
Output: {c}
func (Set[T]) IntersectionIter ¶
IntersectionIter returns set that consists of items that are in both set and iterable.
Example ¶
a := []string{"a", "b", "c"}
m := map[string]int{"c": 0, "d": 1, "e": 2}
s := set.FromSlice(a...)
u := s.IntersectionIter(maps.Keys(m))
fmt.Printf("%v", u)
Output: {c}
func (Set[T]) Iter ¶
Iter returns an iterator over the set.
Example ¶
s := set.FromSlice("a", "b", "c")
t := []string{}
for k := range s.Iter() {
t = append(t, k)
}
slices.Sort(t)
fmt.Printf(
"%d %v",
len(t),
t,
)
Output: 3 [a b c]
func (Set[T]) List ¶
func (s Set[T]) List() []T
List returns the set as the original array. Order is not preserved.
Example ¶
s := set.FromSlice("a", "b")
name := fmt.Sprintf("%v", s.List())
re := regexp.MustCompile(`^(\[a b\]|\[b a\])$`)
fmt.Println(re.Match([]byte(name)))
Output: true
func (Set[T]) Remove ¶
func (s Set[T]) Remove(items ...T)
Remove removes items from a set.
Example ¶
s := set.FromSlice("a", "b", "c")
s.Remove("b", "c")
fmt.Printf(
"%d %t %t %t",
len(s),
s.Contains("a"),
s.Contains("b"),
s.Contains("c"),
)
Output: 1 true false false
func (Set[T]) String ¶ added in v0.2.0
String returns a string representation of a set.
Example ¶
s := set.FromSlice("a", "b")
name := s.String()
re := regexp.MustCompile(`^({a b}|{b a})$`)
fmt.Println(re.Match([]byte(name)))
Output: true
Example (Nil) ¶
var s set.Set[int]
fmt.Printf("%v", s)
Output: {}
func (Set[T]) Sub ¶ added in v1.0.0
Sub returns true if other is a subset of set.
Example ¶
a := []int{1, 2}
b := []int{1, 2}
s := set.FromSlice(a...)
t := set.FromSlice(b...)
fmt.Printf(
"%t",
s.Sub(t),
)
Output: true
Example (Larger) ¶
a := []int{1, 2, 3}
b := []int{1, 2}
s := set.FromSlice(a...)
t := set.FromSlice(b...)
fmt.Printf(
"%t",
s.Sub(t),
)
Output: true
Example (Not) ¶
a := []int{1, 2, 3}
b := []int{1, 4}
s := set.FromSlice(a...)
t := set.FromSlice(b...)
fmt.Printf(
"%t",
s.Sub(t),
)
Output: false
Example (Smaller) ¶
a := []int{1, 2}
b := []int{1, 2, 3}
s := set.FromSlice(a...)
t := set.FromSlice(b...)
fmt.Printf(
"%t",
s.Sub(t),
)
Output: false
func (Set[T]) SymmetricDifference ¶
SymmetricDifference returns set that consists of items that are in each set but not in both sets.
Example ¶
a := []string{"a", "b", "c"}
m := []string{"c", "d", "e"}
s := set.FromSlice(a...)
t := set.FromSlice(m...)
u := s.SymmetricDifference(t)
fmt.Printf(
"%d %t %t %t %t %t",
len(u),
u.Contains("a"),
u.Contains("b"),
u.Contains("c"),
u.Contains("d"),
u.Contains("e"),
)
Output: 4 true true false true true
func (Set[T]) Union ¶
Union returns set that consists of items that are in either of the 2 sets.
Example ¶
a := []string{"a", "b", "c"}
m := []string{"c", "d", "e"}
s := set.FromSlice(a...)
t := set.FromSlice(m...)
u := s.Union(t)
fmt.Printf(
"%d %t %t %t %t %t",
len(u),
u.Contains("a"),
u.Contains("b"),
u.Contains("c"),
u.Contains("d"),
u.Contains("e"),
)
Output: 5 true true true true true
Example (Int) ¶
a := []int{1, 2, 3}
m := []int{3, 4, 5}
s := set.FromSlice(a...)
t := set.FromSlice(m...)
u := s.Union(t)
fmt.Printf(
"%d %t %t %t %t %t",
len(u),
u.Contains(1),
u.Contains(2),
u.Contains(3),
u.Contains(4),
u.Contains(5),
)
Output: 5 true true true true true
Example (Struct) ¶
type testStruct struct {
name string
index int
}
oneTestStruct := testStruct{"one", 1}
twoTestStruct := testStruct{"two", 2}
threeTestStruct := testStruct{"three", 3}
fourTestStruct := testStruct{"four", 4}
fiveTestStruct := testStruct{"five", 5}
a := []testStruct{oneTestStruct, twoTestStruct, threeTestStruct}
m := []testStruct{threeTestStruct, fourTestStruct, fiveTestStruct}
s := set.FromSlice(a...)
t := set.FromSlice(m...)
u := s.Union(t)
fmt.Printf(
"%d %t %t %t %t %t",
len(u),
u.Contains(oneTestStruct),
u.Contains(twoTestStruct),
u.Contains(threeTestStruct),
u.Contains(fourTestStruct),
u.Contains(fiveTestStruct),
)
Output: 5 true true true true true
func (Set[T]) UnionIter ¶
UnionIter returns set that consists of items that are in either the set or iterable.
Example ¶
a := []string{"a", "b", "c"}
m := map[string]int{"c": 0, "d": 1, "e": 2}
s := set.FromSlice(a...)
u := s.UnionIter(maps.Keys(m))
fmt.Printf(
"%d %t %t %t %t %t",
len(u),
u.Contains("a"),
u.Contains("b"),
u.Contains("c"),
u.Contains("d"),
u.Contains("e"),
)
Output: 5 true true true true true