228 lines
5.9 KiB
Go
228 lines
5.9 KiB
Go
// Copyright 2017 Google Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
package sets
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// IntSet stores a set of unique int elements.
|
|
type IntSet struct {
|
|
set map[int]present
|
|
}
|
|
|
|
// NewIntSet creates an IntSet containing the supplied initial int elements.
|
|
func NewIntSet(elements ...int) *IntSet {
|
|
s := &IntSet{}
|
|
s.set = make(map[int]present)
|
|
s.Insert(elements...)
|
|
return s
|
|
}
|
|
|
|
// Copy returns a newly allocated copy of the supplied IntSet.
|
|
func (s *IntSet) Copy() *IntSet {
|
|
c := NewIntSet()
|
|
if s != nil {
|
|
for e := range s.set {
|
|
c.set[e] = present{}
|
|
}
|
|
}
|
|
return c
|
|
}
|
|
|
|
// Insert zero or more int elements into the IntSet. As expected for a Set,
|
|
// elements already present in the IntSet are simply ignored.
|
|
func (s *IntSet) Insert(elements ...int) {
|
|
for _, e := range elements {
|
|
s.set[e] = present{}
|
|
}
|
|
}
|
|
|
|
// Delete zero or more int elements from the IntSet. Any elements not present
|
|
// in the IntSet are simply ignored.
|
|
func (s *IntSet) Delete(elements ...int) {
|
|
for _, e := range elements {
|
|
delete(s.set, e)
|
|
}
|
|
}
|
|
|
|
// Intersect returns a new IntSet containing the intersection of the receiver
|
|
// and argument IntSets. Returns an empty set if the argument is nil.
|
|
func (s *IntSet) Intersect(other *IntSet) *IntSet {
|
|
if other == nil {
|
|
return NewIntSet()
|
|
}
|
|
|
|
// Point a and b to the maps, setting a to the smaller of the two.
|
|
a, b := s.set, other.set
|
|
if len(b) < len(a) {
|
|
a, b = b, a
|
|
}
|
|
|
|
// Perform the intersection.
|
|
intersect := NewIntSet()
|
|
for e := range a {
|
|
if _, ok := b[e]; ok {
|
|
intersect.set[e] = present{}
|
|
}
|
|
}
|
|
return intersect
|
|
}
|
|
|
|
// Disjoint returns true if the intersection of the receiver and the argument
|
|
// IntSets is the empty set. Returns true if the argument is nil or either
|
|
// IntSet is the empty set.
|
|
func (s *IntSet) Disjoint(other *IntSet) bool {
|
|
if other == nil || len(other.set) == 0 || len(s.set) == 0 {
|
|
return true
|
|
}
|
|
|
|
// Point a and b to the maps, setting a to the smaller of the two.
|
|
a, b := s.set, other.set
|
|
if len(b) < len(a) {
|
|
a, b = b, a
|
|
}
|
|
|
|
// Check for non-empty intersection.
|
|
for e := range a {
|
|
if _, ok := b[e]; ok {
|
|
return false // Early-exit because intersecting.
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Difference returns a new IntSet containing the elements in the receiver that
|
|
// are not present in the argument IntSet. Returns a copy of the receiver if
|
|
// the argument is nil.
|
|
func (s *IntSet) Difference(other *IntSet) *IntSet {
|
|
if other == nil {
|
|
return s.Copy()
|
|
}
|
|
|
|
// Insert only the elements in the receiver that are not present in the
|
|
// argument IntSet.
|
|
diff := NewIntSet()
|
|
for e := range s.set {
|
|
if _, ok := other.set[e]; !ok {
|
|
diff.set[e] = present{}
|
|
}
|
|
}
|
|
return diff
|
|
}
|
|
|
|
// Unique returns a new IntSet containing the elements in the receiver that are
|
|
// not present in the argument IntSet *and* the elements in the argument IntSet
|
|
// that are not in the receiver. Returns a copy of the receiver if the argument
|
|
// is nil.
|
|
func (s *IntSet) Unique(other *IntSet) *IntSet {
|
|
if other == nil {
|
|
return s.Copy()
|
|
}
|
|
|
|
sNotInOther := s.Difference(other)
|
|
otherNotInS := other.Difference(s)
|
|
|
|
// Duplicate Union implementation here to avoid extra Copy, since both
|
|
// sNotInOther and otherNotInS are already copies.
|
|
unique := sNotInOther
|
|
for e := range otherNotInS.set {
|
|
unique.set[e] = present{}
|
|
}
|
|
return unique
|
|
}
|
|
|
|
// Equal returns true if the receiver and the argument IntSet contain exactly
|
|
// the same elements. Returns false if the argument is nil.
|
|
func (s *IntSet) Equal(other *IntSet) bool {
|
|
if s == nil || other == nil {
|
|
return s == nil && other == nil
|
|
}
|
|
|
|
// Two sets of different length cannot have the exact same unique
|
|
// elements.
|
|
if len(s.set) != len(other.set) {
|
|
return false
|
|
}
|
|
|
|
// Only one loop is needed. If the two sets are known to be of equal
|
|
// length, then the two sets are equal only if exactly all of the
|
|
// elements in the first set are found in the second.
|
|
for e := range s.set {
|
|
if _, ok := other.set[e]; !ok {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Union returns a new IntSet containing the union of the receiver and argument
|
|
// IntSets. Returns a copy of the receiver if the argument is nil.
|
|
func (s *IntSet) Union(other *IntSet) *IntSet {
|
|
union := s.Copy()
|
|
if other != nil {
|
|
for e := range other.set {
|
|
union.set[e] = present{}
|
|
}
|
|
}
|
|
return union
|
|
}
|
|
|
|
// Contains returns true if element is in the IntSet.
|
|
func (s *IntSet) Contains(element int) bool {
|
|
_, in := s.set[element]
|
|
return in
|
|
}
|
|
|
|
// Len returns the number of unique elements in the IntSet.
|
|
func (s *IntSet) Len() int {
|
|
return len(s.set)
|
|
}
|
|
|
|
// Empty returns true if the receiver is the empty set.
|
|
func (s *IntSet) Empty() bool {
|
|
return len(s.set) == 0
|
|
}
|
|
|
|
// Elements returns a []int of the elements in the IntSet, in no particular (or
|
|
// consistent) order.
|
|
func (s *IntSet) Elements() []int {
|
|
elements := []int{} // Return at least an empty slice rather than nil.
|
|
for e := range s.set {
|
|
elements = append(elements, e)
|
|
}
|
|
return elements
|
|
}
|
|
|
|
// Sorted returns a sorted []int of the elements in the IntSet.
|
|
func (s *IntSet) Sorted() []int {
|
|
elements := s.Elements()
|
|
sort.Ints(elements)
|
|
return elements
|
|
}
|
|
|
|
// String formats the IntSet elements as sorted ints, representing them in
|
|
// "array initializer" syntax.
|
|
func (s *IntSet) String() string {
|
|
elements := s.Sorted()
|
|
var quoted []string
|
|
for _, e := range elements {
|
|
quoted = append(quoted, fmt.Sprintf("\"%d\"", e))
|
|
}
|
|
return fmt.Sprintf("{%s}", strings.Join(quoted, ", "))
|
|
}
|