Files
MonkeyCode/backend/pkg/cvt/cvt.go
2025-06-25 15:56:22 +08:00

257 lines
4.5 KiB
Go

package cvt
import (
"slices"
)
// Iter 用来迭代类型T的列表, 然后返回类型为R的列表
func Iter[T any, R any](ts []T, fn func(int, T) R) []R {
r := make([]R, len(ts))
for i, v := range ts {
r[i] = fn(i, v)
}
return r
}
// IterToMap 迭代类型T的列表, 然后转换成一个 map[K]V.
// K: 可以是任何可比较的值
// V: 是任务类型
func IterToMap[T any, K comparable, V any](ts []T, fn func(int, T) (K, V)) map[K]V {
m := make(map[K]V)
for i, v := range ts {
k, v := fn(i, v)
m[k] = v
}
return m
}
// ForEach 简单的迭代
func ForEach[T any](ts []T, fn func(int, T)) {
for i, t := range ts {
fn(i, t)
}
}
// Filter 过滤迭代
func Filter[T any, R any](ts []T, fn func(int, T) (R, bool)) []R {
r := make([]R, 0)
for i, v := range ts {
if res, ok := fn(i, v); ok {
r = append(r, res)
}
}
return r
}
// Unique 去重
func Unique[T comparable](ts []T) []T {
m := make(map[T]struct{})
news := make([]T, 0)
for _, v := range ts {
if _, ok := m[v]; ok {
continue
}
m[v] = struct{}{}
news = append(news, v)
}
return news
}
// UniqueFn 根据fn去重
func UniqueFn[T any, K comparable](ts []T, fn func(T) K) []T {
m := make(map[K]struct{})
news := make([]T, 0)
for _, v := range ts {
k := fn(v)
if _, ok := m[k]; ok {
continue
}
m[k] = struct{}{}
news = append(news, v)
}
return news
}
// Union 并集
func Union[T comparable](a, b []T) []T {
return Unique(append(a, b...))
}
// Intersection 交集
func Intersection[T comparable](a, b []T) []T {
return Filter(a, func(i int, t T) (T, bool) {
return t, slices.Contains(b, t)
})
}
// Difference 差集
func Difference[T comparable](a, b []T) []T {
return Filter(a, func(i int, t T) (T, bool) {
return t, !slices.Contains(b, t)
})
}
// GroupBy 分组
func GroupBy[T any, K comparable, V any](collection []T, fn func(item T) (K, V)) map[K][]V {
result := map[K][]V{}
for _, item := range collection {
k, v := fn(item)
result[k] = append(result[k], v)
}
return result
}
// SumBy 求和
func SumBy[K comparable, T any](ts []T, fn func(item T) K) map[K]int64 {
result := map[K]int64{}
for _, item := range ts {
k := fn(item)
result[k]++
}
return result
}
// MapToList map 转成 slice
func MapToList[K comparable, V any, R any](m map[K]V, fn func(K, V) R) []R {
r := make([]R, 0)
for k, v := range m {
r = append(r, fn(k, v))
}
return r
}
// NilWithZero t不为nil则执行fn. 否则返回类型为R的空值
func NilWithZero[T any, R any](t *T, fn func(*T) R) R {
if t != nil {
return fn(t)
}
var b R
return b
}
// ZeroWithDefault 给t一个默认值def
func ZeroWithDefault[T comparable](t T, def T) T {
var zero T
if t == zero {
return def
}
return t
}
// NilWithDefault 给空指针t一个默认值def
func NilWithDefault[T any](t, def *T) *T {
if t != nil {
return t
}
return def
}
// Contains 列表包含
func Contains[T any](ts []T, fn func(T) bool) bool {
return slices.ContainsFunc(ts, fn)
}
// GetN 安全获取slice的索引值. 没有返回空值
func GetN[T any](ts []T, i int) T {
if len(ts) > i {
return ts[i]
}
var t T
return t
}
// RangeByStep 步进ts
func RangeByStep[T any](ts []T, step int, fn func([]T)) {
for len(ts) > 0 {
if len(ts) < step {
fn(ts)
ts = nil
} else {
fn(ts[:step])
ts = ts[step:]
}
}
}
// EqualIfNotZero 当b不为空时, 进行比较操作
func EqualIfNotZero[T comparable](a, b T) bool {
var zero T
if b == zero {
return true
}
return a == b
}
// CanditionVar 条件变量
func CanditionVar[T any](fn ...func() (T, bool)) T {
var t T
for _, f := range fn {
if v, ok := f(); ok {
return v
}
}
return t
}
type Identifier interface {
GetID() string
}
// TopN 根据ID获取出现次数最多的前n个
func TopN[T Identifier](ts []T, n int) []T {
all := make(map[string]T)
counter := make(map[string]int)
for _, t := range ts {
counter[t.GetID()]++
all[t.GetID()] = t
}
res := make([]T, 0)
for i := 0; i < n; i++ {
maxID := ""
maxC := 0
for k, c := range counter {
if c > maxC {
maxC = c
maxID = k
}
}
if maxID == "" {
break
}
res = append(res, all[maxID])
delete(counter, maxID)
}
return res
}
// Assert 段言a的类型是否为T, 如何不是返回类型为T的空值
func Assert[T any](a any) T {
if t, ok := a.(T); ok {
return t
}
var t T
return t
}
type Fromer[A, B any] interface {
From(a A) B
}
// From 从A对象转换为B对象
func From[A, B any](a A, f Fromer[A, B]) B {
return f.From(a)
}
// Zero 返回类型为T的空值
func Zero[T any]() *T {
var zero T
return &zero
}