go-study/iterator/set.go

109 lines
1.8 KiB
Go
Raw Permalink Normal View History

2024-11-12 14:52:48 +08:00
package iterator
import (
"iter"
"slices"
2024-11-12 14:52:48 +08:00
)
// Set 集合
2024-11-12 14:52:48 +08:00
type Set[T comparable] struct {
m map[T]struct{}
}
// OrderedSet 有序集合
type OrderedSet[T comparable] struct {
2024-11-12 14:52:48 +08:00
ordered []T // 用于保持顺序
Set[T]
}
func NewSet[T comparable]() Set[T] {
return Set[T]{make(map[T]struct{})}
2024-11-12 14:52:48 +08:00
}
func NewOrderedSet[T comparable]() *OrderedSet[T] {
return &OrderedSet[T]{make([]T, 0), NewSet[T]()}
}
func (s Set[T]) FromSlice(slice []T) {
for v := range slices.Values(slice) {
s.Add(v)
}
}
func (s *OrderedSet[T]) FromSlice(slice []T) {
for v := range slices.Values(slice) {
s.Add(v)
}
}
func (s Set[T]) Add(e T) {
s.m[e] = struct{}{}
2024-11-12 14:52:48 +08:00
}
func (s *OrderedSet[T]) Add(e T) {
2024-11-12 14:52:48 +08:00
if !s.Contains(e) {
s.ordered = append(s.ordered, e)
}
s.m[e] = struct{}{}
}
func (s Set[T]) Remove(e T) {
delete(s.m, e)
}
func (s *OrderedSet[T]) Remove(e T) {
2024-11-12 14:52:48 +08:00
for k, v := range s.ordered {
if v == e {
s.ordered = append(s.ordered[:k], s.ordered[k+1:]...)
break
}
}
delete(s.m, e)
}
func (s Set[T]) Contains(e T) bool {
2024-11-12 14:52:48 +08:00
_, ok := s.m[e]
return ok
}
func (s Set[T]) Len() int {
2024-11-12 14:52:48 +08:00
return len(s.m)
}
func (s Set[T]) All() iter.Seq[T] {
return s.FilterMap(func(T) bool {
return true
})
}
// All 有序集合的推迭代器该方法不能省略否则会走到子集合的FilterMap方法中去
func (s *OrderedSet[T]) All() iter.Seq[T] {
return s.FilterMap(func(T) bool {
return true
})
2024-11-12 14:52:48 +08:00
}
// FilterMap 筛选迭代
func (s Set[T]) FilterMap(fn func(T) bool) iter.Seq[T] {
return func(yield func(T) bool) {
for v := range s.m {
2024-11-15 20:05:34 +08:00
if fn(v) && !yield(v) {
return
}
}
}
}
// FilterMap 筛选迭代
func (s *OrderedSet[T]) FilterMap(fn func(T) bool) iter.Seq[T] {
return func(yield func(T) bool) {
// 迭代有序切片
for v := range slices.Values(s.ordered) {
2024-11-15 20:05:34 +08:00
if fn(v) && !yield(v) {
return
}
}
}
}