|
|
|
// Copyright (c) 2023 Braydon Kains
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
|
// this software and associated documentation files (the "Software"), to deal in
|
|
|
|
// the Software without restriction, including without limitation the rights to
|
|
|
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
// subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in all
|
|
|
|
// copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
|
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
package collections
|
|
|
|
|
|
|
|
// Set is a type alias over a map to an empty struct. This allows a nice
|
|
|
|
// API over the hash map functionality already available, where you can instead
|
|
|
|
// view the set as a single dimension collection and save a lot of clutter of
|
|
|
|
// empty struct initialization any time you add to the set.
|
|
|
|
type Set[T comparable] map[T]struct{}
|
|
|
|
|
|
|
|
// Initialize a new Set with a set of arguments. Good for if you want to initialize
|
|
|
|
// a new set in place with values.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(n)
|
|
|
|
// Space Complexity: O(n)
|
|
|
|
// Allocations: 1 slice, n elements (variadic function argument). 1 set, n elements.
|
|
|
|
func NewSet[T comparable](elements ...T) Set[T] {
|
|
|
|
set := make(Set[T], len(elements))
|
|
|
|
for i := 0; i < len(elements); i++ {
|
|
|
|
set.Add(elements[i])
|
|
|
|
}
|
|
|
|
return set
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize a new Set with a slice. Good for if you already have a slice and want a
|
|
|
|
// set with its values (saves an allocation over NewSet). This function will toss
|
|
|
|
// duplicate values, see NewSetSaveDuplicates if you need to retain duplicate info.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(n)
|
|
|
|
// Space Complexity: O(n)
|
|
|
|
// Allocations: 1 slice, n elements (variadic function argument). 1 set, n elements.
|
|
|
|
func NewSetFromSlice[T comparable](sl []T) Set[T] {
|
|
|
|
set := make(Set[T], len(sl))
|
|
|
|
for i := 0; i < len(sl); i++ {
|
|
|
|
set.Add(sl[i])
|
|
|
|
}
|
|
|
|
return set
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize a new set while preserving the elements that were found to be duplicate.
|
|
|
|
// The duplicate slice will be nil if there are no duplicates to save on allocations.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(n)
|
|
|
|
// Space Complexity: O(n)
|
|
|
|
// Allocations (best case): 1 set, n elements
|
|
|
|
// Allocations (worst case): 1 set, n/2 elements, 2 slices, one with n-1 space, the
|
|
|
|
// second is the first one resized if necessary.
|
|
|
|
func NewSetSaveDuplicates[T comparable](slice []T) (Set[T], []T) {
|
|
|
|
set := make(Set[T], len(slice))
|
|
|
|
var dupes []T = nil
|
|
|
|
dupesIdx := 0
|
|
|
|
for _, el := range slice {
|
|
|
|
if set.Contains(el) {
|
|
|
|
if dupes == nil {
|
|
|
|
// Now that we know there is at least one dupe, we can make the allocation.
|
|
|
|
// The max possible size of the duplicate array is n-1 (aka a slice where
|
|
|
|
// every element is the same).
|
|
|
|
dupes = make([]T, len(slice)-1)
|
|
|
|
}
|
|
|
|
dupes[dupesIdx] = el
|
|
|
|
dupesIdx++
|
|
|
|
} else {
|
|
|
|
set[el] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if dupes != nil && dupesIdx < len(dupes)-1 {
|
|
|
|
dupes = dupes[:dupesIdx]
|
|
|
|
}
|
|
|
|
return set, dupes
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToSlice will take all of the elements of the set and create a new slice out of them.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(n)
|
|
|
|
// Space Complexity: O(n)
|
|
|
|
// Allocations: 1 slice, n elements
|
|
|
|
func (set Set[T]) ToSlice() []T {
|
|
|
|
slice := make([]T, len(set))
|
|
|
|
i := 0
|
|
|
|
for el := range set {
|
|
|
|
slice[i] = el
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
return slice
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add an element to the set.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(1)
|
|
|
|
// Space Complexity: O(1)
|
|
|
|
// Allocations: Set resize
|
|
|
|
func (s Set[T]) Add(el T) {
|
|
|
|
s[el] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove an element from the set.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(1)
|
|
|
|
// Space Complexity: O(1)
|
|
|
|
// Allocations: Set resize
|
|
|
|
func (s Set[T]) Remove(el T) {
|
|
|
|
delete(s, el)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the set contains a particular value.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(1)
|
|
|
|
// Space Complexity: O(1)
|
|
|
|
// Allocations: None
|
|
|
|
func (s Set[T]) Contains(el T) bool {
|
|
|
|
_, containsEl := s[el]
|
|
|
|
return containsEl
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creates a Clone of the set which contains all the same values.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(n)
|
|
|
|
// Space Complexity: O(n)
|
|
|
|
// Allocations: 1 set of n elements
|
|
|
|
func (s Set[T]) Clone() Set[T] {
|
|
|
|
clone := make(Set[T], len(s))
|
|
|
|
for el := range s {
|
|
|
|
clone.Add(el)
|
|
|
|
}
|
|
|
|
return clone
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checks if the set is equal to another.
|
|
|
|
//
|
|
|
|
// Time Complexity: O(n)
|
|
|
|
// Space Complexity: O(1)
|
|
|
|
// Allocations: None
|
|
|
|
func (s Set[T]) Equals(s2 Set[T]) bool {
|
|
|
|
if len(s) != len(s2) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for el := range s {
|
|
|
|
if !s2.Contains(el) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|