Skip to content

Instantly share code, notes, and snippets.

@zachmu
Last active June 26, 2024 17:29
Show Gist options
  • Save zachmu/99e1d4c7701265004cbb898ff395de1f to your computer and use it in GitHub Desktop.
Save zachmu/99e1d4c7701265004cbb898ff395de1f to your computer and use it in GitHub Desktop.
package main
import (
"log"
"sort"
)
// Interface type used for vars
type Sortable[T comparable] interface {
Less(member T) bool
}
// Type set used only for constraints, not vars
type SortableConstraint[T comparable] interface {
comparable
Sortable[T]
}
type Name struct {
First string
Last string
}
var _ Sortable[Name] = Name{}
func (n Name) Less(member Name) bool {
return n.First < member.First || n.First == member.First && n.Last < member.Last
}
type SortableSet[T SortableConstraint[T]] interface {
Add(member T)
Size() int
Contains(member T) bool
Sorted() []T
}
type MapSet[T SortableConstraint[T]] struct {
members map[T]struct{}
}
func NewMapSet[T SortableConstraint[T]]() SortableSet[T] {
return MapSet[T]{
members: make(map[T]struct{}),
}
}
func (s MapSet[T]) Add(member T) {
s.members[member] = struct{}{}
}
func (s MapSet[T]) Size() int {
return len(s.members)
}
func (s MapSet[T]) Contains(member T) bool {
_, found := s.members[member]
return found
}
func (s MapSet[T]) Sorted() []T {
sorted := make([]T, 0, len(s.members))
for member := range s.members {
sorted = append(sorted, member)
}
sort.Slice(sorted, func(i, j int) bool {
return sorted[i].Less(sorted[j])
})
return sorted
}
type SliceSet[T SortableConstraint[T]] struct {
members []T
}
func NewSliceSet[T interface{
Sortable[T]
comparable}]() SortableSet[T] {
return &SliceSet[T]{
members: make([]T, 0),
}
}
func (s *SliceSet[T]) Add(member T) {
if !s.Contains(member) {
s.members = append(s.members, member)
}
}
func (s SliceSet[T]) Size() int {
return len(s.members)
}
func (s SliceSet[T]) Contains(member T) bool {
for _, m := range s.members {
if m == member {
return true
}
}
return false
}
func (s SliceSet[T]) Sorted() []T {
sorted := make([]T, len(s.members))
copy(sorted, s.members)
sort.Slice(sorted, func(i, j int) bool {
return sorted[i].Less(sorted[j])
})
return sorted
}
func main() {
name1 := Name{"John", "Doe"}
name2 := Name{"Jane", "Doe"}
name3 := Name{"Frank", "Reynolds"}
ss := NewSliceSet[Name]()
ms := NewMapSet[Name]()
sets := []SortableSet[Name]{ss, ms}
for _, s := range sets {
s.Add(name1)
s.Add(name2)
s.Add(name2)
if s.Size() != 2 {
log.Fatal("set size is not 2")
}
if !s.Contains(name1) {
log.Fatal("set does not contain name1")
}
if !s.Contains(name2) {
log.Fatal("set does not contain name1")
}
if s.Contains(name3) {
log.Fatal("set contains name3")
}
sorted := ss.Sorted()
expectedSorted := []Name{name2, name1}
if len(sorted) != len(expectedSorted) {
log.Fatal("sorted length does not match")
}
for i := range sorted {
if sorted[i] != expectedSorted[i] {
log.Fatal("sorted does not match")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment