tiny-rdm/backend/utils/coll/set.go

262 lines
4.3 KiB
Go

package coll
import (
"encoding/json"
"fmt"
"sort"
. "tinyrdm/backend/utils"
)
type Void struct{}
// Set 集合, 存放不重复的元素
type Set[T Hashable] map[T]Void
// type Set[T Hashable] struct {
// data map[T]Void
// }
func NewSet[T Hashable](elems ...T) Set[T] {
if len(elems) > 0 {
data := make(Set[T], len(elems))
for _, e := range elems {
data[e] = Void{}
}
return data
} else {
return Set[T]{}
}
}
// Add 添加元素
func (s Set[T]) Add(elem T) bool {
if s == nil {
return false
}
if _, exists := s[elem]; !exists {
s[elem] = Void{}
return true
}
return false
}
// AddN 添加多个元素
func (s Set[T]) AddN(elems ...T) int {
if s == nil {
return 0
}
addCount := 0
var exists bool
for _, elem := range elems {
if _, exists = s[elem]; !exists {
s[elem] = Void{}
addCount += 1
}
}
return addCount
}
// Merge 合并其他集合
func (s Set[T]) Merge(other Set[T]) int {
return s.AddN(other.ToSlice()...)
}
// Contains 判断是否存在指定元素
func (s Set[T]) Contains(elem T) bool {
if s == nil {
return false
}
_, exists := s[elem]
return exists
}
// ContainAny 判断是否包含任意元素
func (s Set[T]) ContainAny(elems ...T) bool {
if s == nil {
return false
}
var exists bool
for _, elem := range elems {
if _, exists = s[elem]; exists {
return true
}
}
return false
}
// Equals 判断两个集合内元素是否一致
func (s Set[T]) Equals(other Set[T]) bool {
if s.Size() != other.Size() {
return false
}
for elem := range s {
if !other.Contains(elem) {
return false
}
}
return true
}
// ContainAll 判断是否包含所有元素
func (s Set[T]) ContainAll(elems ...T) bool {
if s == nil {
return false
}
var exists bool
for _, elem := range elems {
if _, exists = s[elem]; !exists {
return false
}
}
return true
}
// Remove 移除元素
func (s Set[T]) Remove(elem T) bool {
if s == nil {
return false
}
if _, exists := s[elem]; exists {
delete(s, elem)
return true
}
return false
}
// RemoveN 移除多个元素
func (s Set[T]) RemoveN(elems ...T) int {
if s == nil {
return 0
}
var exists bool
removeCnt := 0
for _, elem := range elems {
if _, exists = s[elem]; exists {
delete(s, elem)
removeCnt += 1
}
}
return removeCnt
}
// RemoveSub 移除子集
func (s Set[T]) RemoveSub(subSet Set[T]) int {
if s == nil {
return 0
}
var exists bool
removeCnt := 0
for elem := range subSet {
if _, exists = s[elem]; exists {
delete(s, elem)
removeCnt += 1
}
}
return removeCnt
}
// Filter 根据条件筛出符合的元素
func (s Set[T]) Filter(filterFunc func(i T) bool) []T {
ret := []T{}
for v := range s {
if filterFunc(v) {
ret = append(ret, v)
}
}
return ret
}
// Size 集合长度
func (s Set[T]) Size() int {
return len(s)
}
// IsEmpty 判断是否为空
func (s Set[T]) IsEmpty() bool {
return len(s) <= 0
}
// Clear 清空集合
func (s Set[T]) Clear() {
for elem := range s {
delete(s, elem)
}
}
// ToSlice 转为切片
func (s Set[T]) ToSlice() []T {
size := len(s)
if size <= 0 {
return []T{}
}
ret := make([]T, 0, size)
for elem := range s {
ret = append(ret, elem)
}
return ret
}
// ToSortedSlice 转为排序好的切片
func (s Set[T]) ToSortedSlice(sortFunc func(v1, v2 T) bool) []T {
list := s.ToSlice()
sort.Slice(list, func(i, j int) bool {
return sortFunc(list[i], list[j])
})
return list
}
// Each 遍历检索每个元素
func (s Set[T]) Each(eachFunc func(T)) {
if len(s) <= 0 {
return
}
for elem := range s {
eachFunc(elem)
}
}
// Clone 克隆
func (s Set[T]) Clone() Set[T] {
if s == nil {
return nil
}
other := NewSet[T]()
for elem := range s {
other[elem] = Void{}
}
return other
}
func (s Set[T]) String() string {
arr := s.ToSlice()
return fmt.Sprintf("%v", arr)
}
// MarshalJSON to output non base64 encoded []byte
func (s Set[T]) MarshalJSON() ([]byte, error) {
if s == nil {
return []byte("null"), nil
}
t := s.ToSlice()
return json.Marshal(t)
}
// UnmarshalJSON to deserialize []byte
func (s *Set[T]) UnmarshalJSON(b []byte) error {
t := []T{}
err := json.Unmarshal(b, &t)
if err != nil {
*s = NewSet[T]()
} else {
*s = NewSet[T](t...)
}
return nil
}
// GormDataType gorm common data type
func (s Set[T]) GormDataType() string {
return "json"
}