diff --git a/server/server.go b/server/server.go index fed11f3..e8e0ded 100644 --- a/server/server.go +++ b/server/server.go @@ -452,7 +452,7 @@ func (srv *Server) low(message *Message, present time.Time, expect time.Duration fields = append(fields, log.String("type", messageNames[message.t]), log.String("cost", cost.String()), log.String("message", message.String())) fields = append(fields, message.marks...) //fields = append(fields, log.Stack("stack")) - log.Warn("ServerLowMessage", sher.SliceCastToAny(fields)...) + log.Warn("ServerLowMessage", sher.ConvertSliceToAny(fields)...) srv.OnMessageLowExecEvent(message, cost) } } diff --git a/utils/sher/cast.go b/utils/sher/cast.go deleted file mode 100644 index 7eae314..0000000 --- a/utils/sher/cast.go +++ /dev/null @@ -1,10 +0,0 @@ -package sher - -// SliceCastToAny 将切片转换为任意类型的切片 -func SliceCastToAny[S ~[]V, V any](s S) []any { - var r = make([]any, len(s)) - for i, v := range s { - r[i] = v - } - return r -} diff --git a/utils/sher/convert.go b/utils/sher/convert.go new file mode 100644 index 0000000..18cf47c --- /dev/null +++ b/utils/sher/convert.go @@ -0,0 +1,55 @@ +package sher + +// ConvertSliceToAny 将切片转换为任意类型的切片 +func ConvertSliceToAny[S ~[]V, V any](s S) []any { + var r = make([]any, len(s)) + for i, v := range s { + r[i] = v + } + return r +} + +// ConvertSliceToIndexMap 将切片转换为索引为键的映射 +func ConvertSliceToIndexMap[S ~[]V, V any](s S) map[int]V { + var r = make(map[int]V, len(s)) + for i, v := range s { + r[i] = v + } + return r +} + +// ConvertSliceToMap 将切片转换为值为键的映射 +func ConvertSliceToMap[S ~[]V, V comparable](s S) map[V]struct{} { + var r = make(map[V]struct{}, len(s)) + for _, v := range s { + r[v] = struct{}{} + } + return r +} + +// ConvertSliceToBoolMap 将切片转换为值为键的映射 +func ConvertSliceToBoolMap[S ~[]V, V comparable](s S) map[V]bool { + var r = make(map[V]bool, len(s)) + for _, v := range s { + r[v] = true + } + return r +} + +// ConvertMapKeysToSlice 将映射的键转换为切片 +func ConvertMapKeysToSlice[M ~map[K]V, K comparable, V any](m M) []K { + var r = make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} + +// ConvertMapValuesToSlice 将映射的值转换为切片 +func ConvertMapValuesToSlice[M ~map[K]V, K comparable, V any](m M) []V { + var r = make([]V, 0, len(m)) + for _, v := range m { + r = append(r, v) + } + return r +} diff --git a/utils/sher/duplicate.go b/utils/sher/duplicate.go new file mode 100644 index 0000000..0d0c699 --- /dev/null +++ b/utils/sher/duplicate.go @@ -0,0 +1,83 @@ +package sher + +// DeduplicateSliceInPlace 去除切片中的重复元素 +func DeduplicateSliceInPlace[S ~[]V, V comparable](s *S) { + if s == nil || len(*s) < 2 { + return + } + + var m = make(map[V]struct{}, len(*s)) + var writeIndex int + for readIndex, v := range *s { + if _, ok := m[v]; !ok { + (*s)[writeIndex] = (*s)[readIndex] + writeIndex++ + m[v] = struct{}{} + } + } + *s = (*s)[:writeIndex] +} + +// DeduplicateSlice 去除切片中的重复元素,返回新切片 +func DeduplicateSlice[S ~[]V, V comparable](s S) S { + if s == nil || len(s) < 2 { + return any(s).(S) + } + + var r = make([]V, 0, len(s)) + var m = make(map[V]struct{}, len(s)) + for _, v := range s { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// DeduplicateSliceInPlaceWithCompare 去除切片中的重复元素,使用自定义的比较函数 +func DeduplicateSliceInPlaceWithCompare[S ~[]V, V any](s *S, compare func(a, b V) bool) { + if s == nil || len(*s) < 2 { + return + } + seen := make(map[int]struct{}) + resultIndex := 0 + for i := range *s { + unique := true + for j := range seen { + if compare((*s)[i], (*s)[j]) { + unique = false // Found a duplicate + break + } + } + if unique { + seen[i] = struct{}{} + (*s)[resultIndex] = (*s)[i] + resultIndex++ + } + } + *s = (*s)[:resultIndex] +} + +// DeduplicateSliceWithCompare 去除切片中的重复元素,使用自定义的比较函数,返回新的切片 +func DeduplicateSliceWithCompare[S ~[]V, V any](s S, compare func(a, b V) bool) S { + if s == nil || compare == nil || len(s) < 2 { + return s + } + seen := make(map[int]struct{}) + var result = make([]V, 0, len(s)) + for i := range s { + unique := true + for j := range result { + if compare(s[i], result[j]) { + unique = false + break + } + } + if unique { + result = append(result, s[i]) + seen[i] = struct{}{} + } + } + return result +} diff --git a/utils/sher/duplicate_test.go b/utils/sher/duplicate_test.go new file mode 100644 index 0000000..6498e20 --- /dev/null +++ b/utils/sher/duplicate_test.go @@ -0,0 +1,118 @@ +package sher_test + +import ( + "github.com/kercylan98/minotaur/utils/sher" + "testing" +) + +func TestDeduplicateSliceInPlace(t *testing.T) { + var cases = []struct { + s []int + expected []int + }{ + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + } + + for _, c := range cases { + sher.DeduplicateSliceInPlace(&c.s) + if len(c.s) != len(c.expected) { + t.Errorf("DeduplicateSliceInPlace(%v) == %v, expected %v", c.s, c.s, c.expected) + } + } +} + +func TestDeduplicateSlice(t *testing.T) { + var cases = []struct { + s []int + expected []int + }{ + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + } + + for _, c := range cases { + sl := len(c.s) + if r := sher.DeduplicateSlice(c.s); len(r) != len(c.expected) || len(c.s) != sl { + t.Errorf("DeduplicateSlice(%v) == %v, expected %v", c.s, r, c.expected) + } + } +} + +func TestDeduplicateSliceInPlaceWithCompare(t *testing.T) { + var cases = []struct { + s []int + expected []int + }{ + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + } + + for _, c := range cases { + sher.DeduplicateSliceInPlaceWithCompare(&c.s, func(a, b int) bool { + return a == b + }) + if len(c.s) != len(c.expected) { + t.Errorf("DeduplicateSliceInPlaceWithCompare(%v) == %v, expected %v", c.s, c.s, c.expected) + } + } +} + +func TestDeduplicateSliceWithCompare(t *testing.T) { + var cases = []struct { + s []int + expected []int + }{ + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + { + s: []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2}, + expected: []int{1, 2, 3, 4, 5, 6, 7, 8, 9}, + }, + } + + for _, c := range cases { + sl := len(c.s) + if r := sher.DeduplicateSliceWithCompare(c.s, func(a, b int) bool { + return a == b + }); len(r) != len(c.expected) || len(c.s) != sl { + t.Errorf("DeduplicateSliceWithCompare(%v) == %v, expected %v", c.s, r, c.expected) + } + } +}