package utils import ( "errors" "github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/grand" ) func FindWithIndex[T any](slice []T, predicate func(item T) bool) (int, *T, bool) { for i := range slice { if predicate(slice[i]) { return i, &slice[i], true } } return -1, nil, false } func LastFourElements[T any](s []T, n1 int) []T { n := len(s) if n <= n1 { // 切片长度小于等于4时,返回整个切片 return s } // 切片长度大于4时,返回最后4个元素(从n-4索引到末尾) return s[n-n1:] } func RemoveLast(s string) string { if s == "" { return "" } runes := []rune(s) return string(runes[:len(runes)-1]) } // ************************** 函数1:核心函数(双数组+int型概率,泛型)************************** // randomByIntProbs 核心概率计算函数:接收任意类型元素数组 + int型概率数组,实现权重随机 // T any:支持任意类型的元素切片,职责单一,只处理纯int概率的核心逻辑 func RandomByIntProbs[T any](natureSet []T, probs []int) (T, error) { // 定义泛型零值,用于错误返回 var zeroT T // 1. 合法性校验:元素数组为空 或 概率数组与元素数组长度不匹配 if len(natureSet) == 0 { return zeroT, errors.New("natureSet is empty") } if len(probs) == 0 || len(natureSet) != len(probs) { // 长度不匹配,降级为等概率随机(兼容原有逻辑) return natureSet[grand.Intn(len(natureSet))], nil } // 2. 校验概率值非负,并计算总概率 totalProb := 0 for i, p := range probs { if p < 0 { return zeroT, errors.New("invalid prob value: index " + gconv.String(i) + " (must be non-negative integer)") } totalProb += p } // 3. 总概率为0,降级为等概率随机 if totalProb == 0 { return natureSet[grand.Intn(len(natureSet))], nil } // 4. 计算前缀和(权重随机核心逻辑) prefixSum := make([]int, len(probs)) prefixSum[0] = probs[0] for i := 1; i < len(probs); i++ { prefixSum[i] = prefixSum[i-1] + probs[i] } // 5. 生成随机数匹配前缀和,返回对应元素 randVal := grand.Intn(totalProb) for i, sum := range prefixSum { if randVal < sum { return natureSet[i], nil } } // 极端情况兜底,返回第一个元素 return natureSet[0], nil } // ************************** 函数2:封装函数(兼容string型概率,泛型)************************** // randomByProbs 兼容原有入参格式:接收任意类型元素数组 + string型概率数组 // 内部完成 string[] -> int[] 的转换,然后调用核心函数 randomByIntProbs func RandomByProbs[T any](natureSet []T, probs []string) (T, error) { //var zeroT T // 1. 若string概率数组为空,直接调用核心函数(核心函数会处理降级逻辑) if len(probs) == 0 { return RandomByIntProbs(natureSet, []int{}) } // 2. string[] 转换为 int[](使用 gconv.Int 完成转换) probInts := make([]int, len(probs)) for i, pStr := range probs { // gconv.Int 灵活转换,失败返回0 probInts[i] = gconv.Int(pStr) } // 3. 调用核心函数,复用概率计算逻辑 return RandomByIntProbs(natureSet, probInts) }