Sortable generic set in Go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package main

import (
"fmt"
"sort"
)

func main() {
ms := NewMapSet[Student]()
ms.Add(Student{23, "a"})
ms.Add(Student{22, "a"})
ms.Add(Student{22, "b"})
fmt.Println(ms.Sorted())
}

type Student struct {
Score int
Name string
}

func (s Student) Less(other Student) bool {
return s.Score < other.Score || s.Name < s.Name
}

type Sortable[T any] interface {
Less(member T) bool
}

type SortableSet[T any] interface {
Add(member T)
Size() int
Contains(member T) bool
Sorted() []T
}

type MapSet[T interface {
Sortable[T]
comparable
}] struct {
members map[T]struct{}
}

func NewMapSet[T interface {
Sortable[T]
comparable
}]() 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 {
// cast required here?
sorted = append(sorted, member)
}

sort.Slice(sorted, func(i, j int) bool {
return sorted[i].Less(sorted[j])
})
return sorted
}