| // 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, ", ")) |
| } |