diff --git a/utils/sher/clone.go b/utils/sher/clone.go new file mode 100644 index 0000000..7586af6 --- /dev/null +++ b/utils/sher/clone.go @@ -0,0 +1,88 @@ +package sher + +import ( + "slices" +) + +// CloneMatrix 克隆二维数组 +func CloneMatrix[S ~[][]V, V any](slice S) S { + if slice == nil { + return nil + } + + var result = make(S, len(slice)) + for i := 0; i < len(slice); i++ { + result[i] = CloneSlice(slice[i]) + } + return result +} + +// CloneSlice 克隆切片,该函数是 slices.Clone 的快捷方式 +func CloneSlice[S ~[]V, V any](slice S) S { + return slices.Clone(slice) +} + +// CloneMap 克隆 map +func CloneMap[M ~map[K]V, K comparable, V any](m M) M { + if m == nil { + return nil + } + + var result = make(M, len(m)) + for k, v := range m { + result[k] = v + } + return result +} + +// CloneSliceN 克隆切片为 n 个切片进行返回 +func CloneSliceN[S ~[]V, V any](slice S, n int) []S { + if slice == nil { + return nil + } + + var result = make([]S, n) + for i := 0; i < n; i++ { + result[i] = CloneSlice(slice) + } + return result +} + +// CloneMapN 克隆 map 为 n 个 map 进行返回 +func CloneMapN[M ~map[K]V, K comparable, V any](m M, n int) []M { + if m == nil { + return nil + } + + var result = make([]M, n) + for i := 0; i < n; i++ { + result[i] = CloneMap(m) + } + return result +} + +// CloneSlices 克隆多个切片 +func CloneSlices[S ~[]V, V any](slices ...S) []S { + if slices == nil { + return nil + } + + var result = make([]S, len(slices)) + for i, slice := range slices { + result[i] = CloneSlice(slice) + } + return result +} + +// CloneMaps 克隆多个 map +func CloneMaps[M ~map[K]V, K comparable, V any](maps ...M) []M { + if maps == nil { + return nil + } + + var result = make([]M, len(maps)) + for i, m := range maps { + result[i] = CloneMap(m) + } + return result +} diff --git a/utils/sher/contains.go b/utils/sher/contains.go new file mode 100644 index 0000000..35aa391 --- /dev/null +++ b/utils/sher/contains.go @@ -0,0 +1,308 @@ +package sher + +import "sort" + +type ComparisonHandler[V any] func(source, target V) bool + +// InSlice 判断切片中是否包含某个元素 +func InSlice[S ~[]V, V any](slice S, v V, handler ComparisonHandler[V]) bool { + if slice == nil { + return false + } + for _, value := range slice { + if handler(v, value) { + return true + } + } + return false +} + +// InSliceByBinarySearch 判断切片中是否包含某个元素,使用二分搜索 +func InSliceByBinarySearch[S ~[]V, V any](slice S, v V, handler ComparisonHandler[V]) bool { + return sort.Search(len(slice), func(i int) bool { + return handler(v, slice[i]) + }) != len(slice) +} + +// AllInSlice 判断切片中是否包含所有元素 +func AllInSlice[S ~[]V, V any](slice S, values []V, handler ComparisonHandler[V]) bool { + if slice == nil { + return false + } + for _, value := range values { + if !InSlice(slice, value, handler) { + return false + } + } + return true +} + +// AllInSliceByBinarySearch 判断切片中是否包含所有元素,使用二分搜索 +func AllInSliceByBinarySearch[S ~[]V, V any](slice S, values []V, handler ComparisonHandler[V]) bool { + if slice == nil { + return false + } + for _, value := range values { + if !InSliceByBinarySearch(slice, value, handler) { + return false + } + } + return true +} + +// AnyInSlice 判断切片中是否包含任意一个元素 +func AnyInSlice[S ~[]V, V any](slice S, values []V, handler ComparisonHandler[V]) bool { + if slice == nil { + return false + } + for _, value := range values { + if InSlice(slice, value, handler) { + return true + } + } + return false +} + +// AnyInSliceByBinarySearch 判断切片中是否包含任意一个元素,使用二分搜索 +func AnyInSliceByBinarySearch[S ~[]V, V any](slice S, values []V, handler ComparisonHandler[V]) bool { + if slice == nil { + return false + } + for _, value := range values { + if InSliceByBinarySearch(slice, value, handler) { + return true + } + } + return false +} + +// InSlices 判断多个切片中是否包含某个元素 +func InSlices[S ~[]V, V any](slices []S, v V, handler ComparisonHandler[V]) bool { + return InSlice(MergeSlices(slices...), v, handler) +} + +// InSlicesByBinarySearch 判断多个切片中是否包含某个元素,使用二分搜索 +func InSlicesByBinarySearch[S ~[]V, V any](slices []S, v V, handler ComparisonHandler[V]) bool { + return InSliceByBinarySearch(MergeSlices(slices...), v, handler) +} + +// AllInSlices 判断多个切片中是否包含所有元素 +func AllInSlices[S ~[]V, V any](slices []S, values []V, handler ComparisonHandler[V]) bool { + return AllInSlice(MergeSlices(slices...), values, handler) +} + +// AllInSlicesByBinarySearch 判断多个切片中是否包含所有元素,使用二分搜索 +func AllInSlicesByBinarySearch[S ~[]V, V any](slices []S, values []V, handler ComparisonHandler[V]) bool { + return AllInSliceByBinarySearch(MergeSlices(slices...), values, handler) +} + +// AnyInSlices 判断多个切片中是否包含任意一个元素 +func AnyInSlices[S ~[]V, V any](slices []S, values []V, handler ComparisonHandler[V]) bool { + return AnyInSlice(MergeSlices(slices...), values, handler) +} + +// AnyInSlicesByBinarySearch 判断多个切片中是否包含任意一个元素,使用二分搜索 +func AnyInSlicesByBinarySearch[S ~[]V, V any](slices []S, values []V, handler ComparisonHandler[V]) bool { + return AnyInSliceByBinarySearch(MergeSlices(slices...), values, handler) +} + +// InAllSlices 判断元素是否在所有切片中都存在 +func InAllSlices[S ~[]V, V any](slices []S, v V, handler ComparisonHandler[V]) bool { + if slices == nil { + return false + } + for _, slice := range slices { + if !InSlice(slice, v, handler) { + return false + } + } + return true +} + +// InAllSlicesByBinarySearch 判断元素是否在所有切片中都存在,使用二分搜索 +func InAllSlicesByBinarySearch[S ~[]V, V any](slices []S, v V, handler ComparisonHandler[V]) bool { + if slices == nil { + return false + } + for _, slice := range slices { + if !InSliceByBinarySearch(slice, v, handler) { + return false + } + } + return true +} + +// AnyInAllSlices 判断元素是否在所有切片中都存在任意至少一个 +func AnyInAllSlices[S ~[]V, V any](slices []S, v []V, handler ComparisonHandler[V]) bool { + if slices == nil { + return false + } + for _, slice := range slices { + if AnyInSlice(slice, v, handler) { + return true + } + } + return false +} + +// AnyInAllSlicesByBinarySearch 判断元素是否在所有切片中都存在任意至少一个,使用二分搜索 +func AnyInAllSlicesByBinarySearch[S ~[]V, V any](slices []S, v []V, handler ComparisonHandler[V]) bool { + if slices == nil { + return false + } + for _, slice := range slices { + if AnyInSliceByBinarySearch(slice, v, handler) { + return true + } + } + return false +} + +// KeyInMap 判断 map 中是否包含某个 key +func KeyInMap[M ~map[K]V, K comparable, V any](m M, key K) bool { + _, ok := m[key] + return ok +} + +// ValueInMap 判断 map 中是否包含某个 value +func ValueInMap[M ~map[K]V, K comparable, V any](m M, value V, handler ComparisonHandler[V]) bool { + if m == nil { + return false + } + for _, v := range m { + if handler(value, v) { + return true + } + } + return false +} + +// AllKeyInMap 判断 map 中是否包含所有 key +func AllKeyInMap[M ~map[K]V, K comparable, V any](m M, keys ...K) bool { + if m == nil { + return false + } + for _, key := range keys { + if !KeyInMap(m, key) { + return false + } + } + return true +} + +// AllValueInMap 判断 map 中是否包含所有 value +func AllValueInMap[M ~map[K]V, K comparable, V any](m M, values []V, handler ComparisonHandler[V]) bool { + if m == nil { + return false + } + for _, value := range values { + if !ValueInMap(m, value, handler) { + return false + } + } + return true +} + +// AnyKeyInMap 判断 map 中是否包含任意一个 key +func AnyKeyInMap[M ~map[K]V, K comparable, V any](m M, keys ...K) bool { + if m == nil { + return false + } + for _, key := range keys { + if KeyInMap(m, key) { + return true + } + } + return false +} + +// AnyValueInMap 判断 map 中是否包含任意一个 value +func AnyValueInMap[M ~map[K]V, K comparable, V any](m M, values []V, handler ComparisonHandler[V]) bool { + if m == nil { + return false + } + for _, value := range values { + if ValueInMap(m, value, handler) { + return true + } + } + return false +} + +// AllKeyInMaps 判断多个 map 中是否包含所有 key +func AllKeyInMaps[M ~map[K]V, K comparable, V any](maps []M, keys ...K) bool { + if maps == nil { + return false + } + for _, m := range maps { + if !AllKeyInMap(m, keys...) { + return false + } + } + return true +} + +// AllValueInMaps 判断多个 map 中是否包含所有 value +func AllValueInMaps[M ~map[K]V, K comparable, V any](maps []M, values []V, handler ComparisonHandler[V]) bool { + if maps == nil { + return false + } + for _, m := range maps { + if !AllValueInMap(m, values, handler) { + return false + } + } + return true +} + +// AnyKeyInMaps 判断多个 map 中是否包含任意一个 key +func AnyKeyInMaps[M ~map[K]V, K comparable, V any](maps []M, keys ...K) bool { + if maps == nil { + return false + } + for _, m := range maps { + if AnyKeyInMap(m, keys...) { + return true + } + } + return false +} + +// AnyValueInMaps 判断多个 map 中是否包含任意一个 value +func AnyValueInMaps[M ~map[K]V, K comparable, V any](maps []M, values []V, handler ComparisonHandler[V]) bool { + if maps == nil { + return false + } + for _, m := range maps { + if AnyValueInMap(m, values, handler) { + return true + } + } + return false +} + +// InAllMaps 判断元素是否在所有 map 中都存在 +func InAllMaps[M ~map[K]V, K comparable, V any](maps []M, key K) bool { + if maps == nil { + return false + } + for _, m := range maps { + if !KeyInMap(m, key) { + return false + } + } + return true +} + +// AnyInAllMaps 判断元素是否在所有 map 中都存在任意至少一个 +func AnyInAllMaps[M ~map[K]V, K comparable, V any](maps []M, keys []K) bool { + if maps == nil { + return false + } + for _, m := range maps { + if AnyKeyInMap(m, keys...) { + return true + } + } + return false +} diff --git a/utils/sher/doc.go b/utils/sher/doc.go new file mode 100644 index 0000000..90d3702 --- /dev/null +++ b/utils/sher/doc.go @@ -0,0 +1,2 @@ +// Package sher 用于对 slice 和 map 操作的工具函数,将逐步替代 utils/slice 和 utils/map +package sher diff --git a/utils/sher/filter.go b/utils/sher/filter.go new file mode 100644 index 0000000..347ca52 --- /dev/null +++ b/utils/sher/filter.go @@ -0,0 +1,137 @@ +package sher + +// FilterOutByIndices 过滤切片中特定索引的元素,返回过滤后的切片 +func FilterOutByIndices[S ~[]V, V any](slice S, indices ...int) S { + if slice == nil { + return nil + } + if len(indices) == 0 { + return slice + } + + excludeMap := make(map[int]bool) + for _, ex := range indices { + excludeMap[ex] = true + } + + validElements := make([]V, 0, len(slice)-len(excludeMap)) + for i, v := range slice { + if !excludeMap[i] { + validElements = append(validElements, v) + } + } + + return validElements +} + +// FilterOutByCondition 过滤切片中符合条件的元素,返回过滤后的切片 +// - condition 的返回值为 true 时,将会过滤掉该元素 +func FilterOutByCondition[S ~[]V, V any](slice S, condition func(v V) bool) S { + if slice == nil { + return nil + } + if condition == nil { + return slice + } + + validElements := make([]V, 0, len(slice)) + for _, v := range slice { + if !condition(v) { + validElements = append(validElements, v) + } + } + + return validElements +} + +// FilterOutByKey 过滤 map 中特定的 key,返回过滤后的 map +func FilterOutByKey[M ~map[K]V, K comparable, V any](m M, key K) M { + if m == nil { + return nil + } + + validMap := make(M, len(m)-1) + for k, v := range m { + if k != key { + validMap[k] = v + } + } + + return validMap +} + +// FilterOutByValue 过滤 map 中特定的 value,返回过滤后的 map +func FilterOutByValue[M ~map[K]V, K comparable, V any](m M, value V, handler ComparisonHandler[V]) M { + if m == nil { + return nil + } + + validMap := make(M, len(m)) + for k, v := range m { + if !handler(value, v) { + validMap[k] = v + } + } + + return validMap +} + +// FilterOutByKeys 过滤 map 中多个 key,返回过滤后的 map +func FilterOutByKeys[M ~map[K]V, K comparable, V any](m M, keys ...K) M { + if m == nil { + return nil + } + if len(keys) == 0 { + return m + } + + validMap := make(M, len(m)-len(keys)) + for k, v := range m { + if !InSlice(keys, k, func(source, target K) bool { + return source == target + }) { + validMap[k] = v + } + } + + return validMap +} + +// FilterOutByValues 过滤 map 中多个 value,返回过滤后的 map +func FilterOutByValues[M ~map[K]V, K comparable, V any](m M, values []V, handler ComparisonHandler[V]) M { + if m == nil { + return nil + } + if len(values) == 0 { + return m + } + + validMap := make(M, len(m)) + for k, v := range m { + if !InSlice(values, v, handler) { + validMap[k] = v + } + } + + return validMap +} + +// FilterOutByMap 过滤 map 中符合条件的元素,返回过滤后的 map +// - condition 的返回值为 true 时,将会过滤掉该元素 +func FilterOutByMap[M ~map[K]V, K comparable, V any](m M, condition func(k K, v V) bool) M { + if m == nil { + return nil + } + if condition == nil { + return m + } + + validMap := make(M, len(m)) + for k, v := range m { + if condition(k, v) { + validMap[k] = v + } + } + + return validMap +} diff --git a/utils/sher/find.go b/utils/sher/find.go new file mode 100644 index 0000000..891ff7a --- /dev/null +++ b/utils/sher/find.go @@ -0,0 +1,91 @@ +package sher + +import "github.com/kercylan98/minotaur/utils/generic" + +// FindMinimumInSlice 获取切片中的最小值 +func FindMinimumInSlice[S ~[]V, V generic.Number](slice S, handler ComparisonHandler[V]) (result V) { + if slice == nil { + return + } + result = slice[0] + for i := 1; i < len(slice); i++ { + if handler(slice[i], result) { + result = slice[i] + } + } + return +} + +// FindMaximumInSlice 获取切片中的最大值 +func FindMaximumInSlice[S ~[]V, V generic.Number](slice S, handler ComparisonHandler[V]) (result V) { + if slice == nil { + return + } + result = slice[0] + for i := 1; i < len(slice); i++ { + if handler(result, slice[i]) { + result = slice[i] + } + } + return +} + +// FindMin2MaxInSlice 获取切片中的最小值和最大值 +func FindMin2MaxInSlice[S ~[]V, V generic.Number](slice S, handler ComparisonHandler[V]) (min, max V) { + if slice == nil { + return + } + min = slice[0] + max = slice[0] + for i := 1; i < len(slice); i++ { + if handler(slice[i], min) { + min = slice[i] + } + if handler(max, slice[i]) { + max = slice[i] + } + } + return +} + +// FindMinFromMap 获取 map 中的最小值 +func FindMinFromMap[M ~map[K]V, K comparable, V generic.Number](m M, handler ComparisonHandler[V]) (result V) { + if m == nil { + return + } + for _, v := range m { + if handler(v, result) { + result = v + } + } + return +} + +// FindMaxFromMap 获取 map 中的最大值 +func FindMaxFromMap[M ~map[K]V, K comparable, V generic.Number](m M, handler ComparisonHandler[V]) (result V) { + if m == nil { + return + } + for _, v := range m { + if handler(result, v) { + result = v + } + } + return +} + +// FindMin2MaxFromMap 获取 map 中的最小值和最大值 +func FindMin2MaxFromMap[M ~map[K]V, K comparable, V generic.Number](m M, handler ComparisonHandler[V]) (min, max V) { + if m == nil { + return + } + for _, v := range m { + if handler(v, min) { + min = v + } + if handler(max, v) { + max = v + } + } + return +} diff --git a/utils/sher/merge.go b/utils/sher/merge.go new file mode 100644 index 0000000..4100abe --- /dev/null +++ b/utils/sher/merge.go @@ -0,0 +1,56 @@ +package sher + +// MergeSlices 合并切片 +func MergeSlices[S ~[]V, V any](slices ...S) (result S) { + if len(slices) == 0 { + return nil + } + + var length int + for _, slice := range slices { + length += len(slice) + } + + result = make(S, 0, length) + for _, slice := range slices { + result = append(result, slice...) + } + return +} + +// MergeMaps 合并 map,当多个 map 中存在相同的 key 时,后面的 map 中的 key 将会覆盖前面的 map 中的 key +func MergeMaps[M ~map[K]V, K comparable, V any](maps ...M) (result M) { + if len(maps) == 0 { + return nil + } + + var length int + for _, m := range maps { + length += len(m) + } + + result = make(M, length) + for _, m := range maps { + for k, v := range m { + result[k] = v + } + } + return +} + +// MergeMapsWithSkip 合并 map,当多个 map 中存在相同的 key 时,后面的 map 中的 key 将会被跳过 +func MergeMapsWithSkip[M ~map[K]V, K comparable, V any](maps ...M) (result M) { + if len(maps) == 0 { + return nil + } + + result = make(M) + for _, m := range maps { + for k, v := range m { + if _, ok := result[k]; !ok { + result[k] = v + } + } + } + return +} diff --git a/utils/sher/random.go b/utils/sher/random.go new file mode 100644 index 0000000..ad360fb --- /dev/null +++ b/utils/sher/random.go @@ -0,0 +1,239 @@ +package sher + +import ( + "fmt" + "github.com/kercylan98/minotaur/utils/random" +) + +// ChooseRandomSliceElementRepeatN 获取切片中的 n 个随机元素,允许重复 +// - 如果 n 大于切片长度或小于 0 时将会发生 panic +func ChooseRandomSliceElementRepeatN[S ~[]V, V any](slice S, n int) (result []V) { + if slice == nil { + return + } + if n > len(slice) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the slice or less than 0, n: %d, length: %d", n, len(slice))) + } + result = make([]V, n) + for i := 0; i < n; i++ { + result[i] = slice[random.Int(0, len(slice)-1)] + } + return +} + +// ChooseRandomIndexRepeatN 获取切片中的 n 个随机元素的索引,允许重复 +// - 如果 n 大于切片长度或小于 0 时将会发生 panic +func ChooseRandomIndexRepeatN[S ~[]V, V any](slice S, n int) (result []int) { + if slice == nil { + return + } + if n > len(slice) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the slice or less than 0, n: %d, length: %d", n, len(slice))) + } + result = make([]int, n) + for i := 0; i < n; i++ { + result[i] = random.Int(0, len(slice)-1) + } + return +} + +// ChooseRandomSliceElement 获取切片中的随机元素 +func ChooseRandomSliceElement[S ~[]V, V any](slice S) (v V) { + if slice == nil { + return + } + return slice[random.Int(0, len(slice)-1)] +} + +// ChooseRandomIndex 获取切片中的随机元素的索引 +func ChooseRandomIndex[S ~[]V, V any](slice S) (index int) { + if slice == nil { + return + } + return random.Int(0, len(slice)-1) +} + +// ChooseRandomSliceElementN 获取切片中的 n 个随机元素 +// - 如果 n 大于切片长度或小于 0 时将会发生 panic +func ChooseRandomSliceElementN[S ~[]V, V any](slice S, n int) (result []V) { + if slice == nil { + return + } + if n > len(slice) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the slice or less than 0, n: %d, length: %d", n, len(slice))) + } + result = make([]V, n) + for i := 0; i < n; i++ { + result[i] = slice[random.Int(0, len(slice)-1)] + } + return +} + +// ChooseRandomIndexN 获取切片中的 n 个随机元素的索引 +// - 如果 n 大于切片长度或小于 0 时将会发生 panic +func ChooseRandomIndexN[S ~[]V, V any](slice S, n int) (result []int) { + if slice == nil { + return + } + if n > len(slice) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the slice or less than 0, n: %d, length: %d", n, len(slice))) + } + result = make([]int, n) + for i := 0; i < n; i++ { + result[i] = random.Int(0, len(slice)-1) + } + return +} + +// ChooseRandomMapKeyRepeatN 获取 map 中的 n 个随机 key,允许重复 +// - 如果 n 大于 map 长度或小于 0 时将会发生 panic +func ChooseRandomMapKeyRepeatN[M ~map[K]V, K comparable, V any](m M, n int) (result []K) { + if m == nil { + return + } + if n > len(m) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the map or less than 0, n: %d, length: %d", n, len(m))) + } + result = make([]K, n) + for i := 0; i < n; i++ { + for k := range m { + result[i] = k + break + } + } + return +} + +// ChooseRandomMapValueRepeatN 获取 map 中的 n 个随机 value,允许重复 +// - 如果 n 大于 map 长度或小于 0 时将会发生 panic +func ChooseRandomMapValueRepeatN[M ~map[K]V, K comparable, V any](m M, n int) (result []V) { + if m == nil { + return + } + if n > len(m) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the map or less than 0, n: %d, length: %d", n, len(m))) + } + result = make([]V, n) + for i := 0; i < n; i++ { + for _, v := range m { + result[i] = v + break + } + } + return +} + +// ChooseRandomMapKeyAndValueRepeatN 获取 map 中的 n 个随机 key 和 value,允许重复 +// - 如果 n 大于 map 长度或小于 0 时将会发生 panic +func ChooseRandomMapKeyAndValueRepeatN[M ~map[K]V, K comparable, V any](m M, n int) M { + if m == nil { + return nil + } + if n > len(m) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the map or less than 0, n: %d, length: %d", n, len(m))) + } + result := make(M, n) + for i := 0; i < n; i++ { + for k, v := range m { + result[k] = v + break + } + } + return result +} + +// ChooseRandomMapKey 获取 map 中的随机 key +func ChooseRandomMapKey[M ~map[K]V, K comparable, V any](m M) (k K) { + if m == nil { + return + } + for k = range m { + return + } + return +} + +// ChooseRandomMapValue 获取 map 中的随机 value +func ChooseRandomMapValue[M ~map[K]V, K comparable, V any](m M) (v V) { + if m == nil { + return + } + for _, v = range m { + return + } + return +} + +// ChooseRandomMapKeyN 获取 map 中的 n 个随机 key +// - 如果 n 大于 map 长度或小于 0 时将会发生 panic +func ChooseRandomMapKeyN[M ~map[K]V, K comparable, V any](m M, n int) (result []K) { + if m == nil { + return + } + if n > len(m) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the map or less than 0, n: %d, length: %d", n, len(m))) + } + result = make([]K, n) + i := 0 + for k := range m { + result[i] = k + i++ + if i == n { + break + } + } + return +} + +// ChooseRandomMapValueN 获取 map 中的 n 个随机 value +// - 如果 n 大于 map 长度或小于 0 时将会发生 panic +func ChooseRandomMapValueN[M ~map[K]V, K comparable, V any](m M, n int) (result []V) { + if m == nil { + return + } + if n > len(m) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the map or less than 0, n: %d, length: %d", n, len(m))) + } + result = make([]V, n) + i := 0 + for _, v := range m { + result[i] = v + i++ + if i == n { + break + } + } + return +} + +// ChooseRandomMapKeyAndValue 获取 map 中的随机 key 和 value +func ChooseRandomMapKeyAndValue[M ~map[K]V, K comparable, V any](m M) (k K, v V) { + if m == nil { + return + } + for k, v = range m { + return + } + return +} + +// ChooseRandomMapKeyAndValueN 获取 map 中的 n 个随机 key 和 value +// - 如果 n 大于 map 长度或小于 0 时将会发生 panic +func ChooseRandomMapKeyAndValueN[M ~map[K]V, K comparable, V any](m M, n int) M { + if m == nil { + return nil + } + if n > len(m) || n < 0 { + panic(fmt.Errorf("n is greater than the length of the map or less than 0, n: %d, length: %d", n, len(m))) + } + result := make(M, n) + i := 0 + for k, v := range m { + result[k] = v + i++ + if i == n { + break + } + } + return result +} diff --git a/utils/sher/sort.go b/utils/sher/sort.go new file mode 100644 index 0000000..0ecc2e6 --- /dev/null +++ b/utils/sher/sort.go @@ -0,0 +1,50 @@ +package sher + +import ( + "github.com/kercylan98/minotaur/utils/generic" + "github.com/kercylan98/minotaur/utils/random" + "sort" +) + +// Desc 对切片进行降序排序 +func Desc[S ~[]V, V any, Sort generic.Ordered](slice *S, getter func(index int) Sort) { + sort.Slice(*slice, func(i, j int) bool { + return getter(i) > getter(j) + }) +} + +// DescByClone 对切片进行降序排序,返回排序后的切片 +func DescByClone[S ~[]V, V any, Sort generic.Ordered](slice S, getter func(index int) Sort) S { + result := CloneSlice(slice) + Desc(&result, getter) + return result + +} + +// Asc 对切片进行升序排序 +func Asc[S ~[]V, V any, Sort generic.Ordered](slice *S, getter func(index int) Sort) { + sort.Slice(*slice, func(i, j int) bool { + return getter(i) < getter(j) + }) +} + +// AscByClone 对切片进行升序排序,返回排序后的切片 +func AscByClone[S ~[]V, V any, Sort generic.Ordered](slice S, getter func(index int) Sort) S { + result := CloneSlice(slice) + Asc(&result, getter) + return result +} + +// Shuffle 对切片进行随机排序 +func Shuffle[S ~[]V, V any](slice *S) { + sort.Slice(*slice, func(i, j int) bool { + return random.Int(0, 1) == 0 + }) +} + +// ShuffleByClone 对切片进行随机排序,返回排序后的切片 +func ShuffleByClone[S ~[]V, V any](slice S) S { + result := CloneSlice(slice) + Shuffle(&result) + return result +}