From d1d47051d679614efc6c24e89ffaf51013a15b93 Mon Sep 17 00:00:00 2001 From: huangzj Date: Tue, 30 Jun 2020 11:47:38 +0800 Subject: [PATCH] =?UTF-8?q?feat(Go-Tool)=EF=BC=9A=20ArrayList=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=B7=B1=E5=BA=A6=E5=A4=8D=E5=88=B6=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E4=BB=A5=E5=8F=8A=E5=8D=95=E6=B5=8B=E7=B1=BB=E3=80=81=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0Rand=E9=9A=8F=E6=9C=BA=E8=8E=B7=E5=8F=96=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E6=96=B9=E6=B3=95=E3=80=81RandByWeight=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=87=8D=E9=9A=8F=E6=9C=BA=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=A5=96=E5=8A=B1=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 4 +- test/array/ArrayUtil_test.go | 17 ++++ test/rand/RandByWeight_test.go | 51 +++++++++++ test/rand/Rand_test.go | 25 +++++ util/array/ArrayUtil.go | 15 +++ util/rand/Rand.go | 61 +++++++++++++ util/rand/RandByWeight.go | 162 +++++++++++++++++++++++++++++++++ 7 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 test/rand/RandByWeight_test.go create mode 100644 test/rand/Rand_test.go create mode 100644 util/rand/Rand.go create mode 100644 util/rand/RandByWeight.go diff --git a/readme.md b/readme.md index 4012ed9..ee8c239 100644 --- a/readme.md +++ b/readme.md @@ -20,4 +20,6 @@ 2020/5/7 : 创建timed包相关时间操作工具,实现时间戳、时间格式化操作。创建timed测试类 -2020/6/15: 创建Set,实现相关方法 \ No newline at end of file +2020/6/15: 创建Set,实现相关方法 + +2020/6/30: ArrayList添加深度复制方法以及单测类、添加Rand随机获取参数方法、RandByWeight根据权重随机获取奖励方法 \ No newline at end of file diff --git a/test/array/ArrayUtil_test.go b/test/array/ArrayUtil_test.go index 0022148..9f7c6a8 100644 --- a/test/array/ArrayUtil_test.go +++ b/test/array/ArrayUtil_test.go @@ -91,6 +91,11 @@ func TestJoin(t *testing.T) { union(mm, mm2) } +func TestEqual(t *testing.T) { + DeepCopyIntSlice() + DeepCopyIntSlice2() +} + func intersection(mm, nn []interface{}) { i1 := array.Intersection(mm, nn) for _, row := range i1 { @@ -116,6 +121,18 @@ func union(mm, nn []interface{}) { } } +func DeepCopyIntSlice() { + src := []int{1, 2, 3, 4, 5, 6} + src1 := array.DeepCopyIntSlice(src) + fmt.Println(&src == &src1) +} + +func DeepCopyIntSlice2() { + src := [][]int{{1, 2, 3}, {4, 5, 6}} + src1 := array.DeepCopyIntSlice2(src) + fmt.Println(&src == &src1) +} + func init() { mm = make([]interface{}, 0) mm1 = make([]interface{}, 0) diff --git a/test/rand/RandByWeight_test.go b/test/rand/RandByWeight_test.go new file mode 100644 index 0000000..79c5f7f --- /dev/null +++ b/test/rand/RandByWeight_test.go @@ -0,0 +1,51 @@ +/* + * @Author : huangzj + * @Time : 2020/6/29 17:16 + * @Description: + */ + +package rand + +import ( + "Go-Tool/util/rand" + "fmt" + "strconv" + "testing" +) + +func TestRandByWeight(t *testing.T) { + fmt.Printf(strconv.Itoa(rand.GetRandValueByWeight([]int{10, 20, 30, 50}))) + + list, list1 := rand.GetAwardByWeight([][]int{{2, 2, 10}, {3, 3, 4}}) + for _, r := range list { + fmt.Println(strconv.Itoa(r)) + } + for _, r := range list1 { + fmt.Println(strconv.Itoa(r)) + } + + fmt.Println(rand.GetByWeight([]int{10, 11, 12, 13}, []int{20, 30, 40, 50})) + + list2, list3 := rand.GetAwardByWeightWithLeftAward([][]int{{2, 3, 30}, {3, 3, 40}}) + for _, r := range list2 { + fmt.Println(strconv.Itoa(r)) + } + for _, r := range list3 { + for _, r1 := range r { + fmt.Println(strconv.Itoa(r1)) + } + } + + list4 := rand.GetCountAwardsFromPool([][]int{{1, 2, 30}, {2, 2, 40}, {3, 2, 50}}, 2) + for _, r := range list4 { + for _, r1 := range r { + fmt.Println(strconv.Itoa(r1)) + } + } + + list5 := rand.GetAwardByPercentage([][]int{{20, 3, 99}, {90, 3, 10}, {12, 3, 22}}, 100) + for _, r := range list5 { + fmt.Println(strconv.Itoa(r)) + } + +} diff --git a/test/rand/Rand_test.go b/test/rand/Rand_test.go new file mode 100644 index 0000000..cc05e30 --- /dev/null +++ b/test/rand/Rand_test.go @@ -0,0 +1,25 @@ +/* + * @Author : huangzj + * @Time : 2020/6/29 17:15 + * @Description: + */ + +package rand + +import ( + "Go-Tool/util/rand" + "fmt" + "strconv" + "testing" +) + +func TestRand(t *testing.T) { + fmt.Printf(strconv.Itoa(rand.GetRandInt(100, 2000))) + for _, r := range rand.GetRandIntNoRepeat(10, 100, 200) { + fmt.Printf(strconv.Itoa(r)) + } + + for _, r := range rand.GetDiffNum([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 10) { + fmt.Printf(strconv.Itoa(r)) + } +} diff --git a/util/array/ArrayUtil.go b/util/array/ArrayUtil.go index 282a734..4fe36f8 100644 --- a/util/array/ArrayUtil.go +++ b/util/array/ArrayUtil.go @@ -104,3 +104,18 @@ func Union(aList, bList []interface{}) []interface{} { } return result } + +func DeepCopyIntSlice(src []int) []int { + var clone = make([]int, len(src)) + copy(clone, src) + return clone +} + +func DeepCopyIntSlice2(src [][]int) [][]int { + var clone = make([][]int, len(src)) + for i := 0; i < len(src); i++ { + clone[i] = DeepCopyIntSlice(src[i]) + } + + return clone +} diff --git a/util/rand/Rand.go b/util/rand/Rand.go new file mode 100644 index 0000000..5e8f7d3 --- /dev/null +++ b/util/rand/Rand.go @@ -0,0 +1,61 @@ +/* + * @Author : huangzj + * @Time : 2020/6/29 10:48 + * @Description:这边的随机获取没有加锁,对于一些需要加锁的场景可以在外面再包装一层 + */ + +package rand + +import ( + "fmt" + "math/rand" +) + +var R *rand.Rand + +//获取min和max之间的一个随机数,返回值范围:[min,max] +func GetRandInt(min int, max int) int { + if min > max { + panic(fmt.Sprint("GetRandInt传入参数无效,min = ", min, ",max = ", max)) + } + //Intn返回的结果是[0,n),所以这边会包含min和max + value := R.Intn(max-min+1) + min + return value +} + +// 随机算出count个数不重复 +func GetRandIntNoRepeat(count, min, max int) []int { + if count > max-min+1 { + panic("数据错误") + } + + randAttr := make([]int, 0) + + // 用于记录以及选中的数 + selected := make(map[int]interface{}, 0) + + for i := 1; i <= count; i++ { + randIndex := GetRandInt(min, max) + if _, ok := selected[randIndex]; ok { + i -= 1 + continue + } + selected[randIndex] = nil + randAttr = append(randAttr, randIndex) + } + + return randAttr +} + +//从一个数组中获取到X个不重复随机数 +func GetDiffNum(data []int, count int) []int { + if count > len(data) { + panic("获取随机数数量有误") + } + diffList := make([]int, 0) + diffListIndex := GetRandIntNoRepeat(count, 0, len(data)-1) + for _, i := range diffListIndex { + diffList = append(diffList, data[i]) + } + return diffList +} diff --git a/util/rand/RandByWeight.go b/util/rand/RandByWeight.go new file mode 100644 index 0000000..0517b81 --- /dev/null +++ b/util/rand/RandByWeight.go @@ -0,0 +1,162 @@ +/* + * @Author : huangzj + * @Time : 2020/6/29 10:23 + * @Description:这边的随机获取没有加锁,对于一些需要加锁的场景可以在外面再包装一层 + */ + +package rand + +import ( + "Go-Tool/util/array" + "math/rand" + "time" +) + +//传入一组包含权重的数组,计算权重,返回对应权重数组的下标(即对应权重获取的结果) +func GetRandValueByWeight(weightList []int) int { + //计算总的权重 + totalWeight := 0 + for _, value := range weightList { + totalWeight += value + } + nowRand := R.Intn(totalWeight) + rate := 0 + for i := 0; i < len(weightList); i++ { + rate += weightList[i] + if nowRand < rate { + return i + } + } + return 0 +} + +//通过权重获取奖励结果,这边的awardList的结构应该是 [[道具Id,道具数量,权重],....] +//返回结果的第一个元素是不包含权重的数组,第二个元素是包含权重的数组 +func GetAwardByWeight(awardList [][]int) ([]int, []int) { + //这边应该加一个数组的检查. + weightListCheck(awardList) + + //最后一位一定是权重. + weight := 0 + for _, v := range awardList { + weight += v[len(v)-1] + } + randNum := GetRandInt(1, weight) + sum := 0 + for _, v := range awardList { + sum += v[len(v)-1] + if sum >= randNum { + result := make([]int, 0) + weightResult := make([]int, 0) + return append(result, v[:len(v)-1]...), append(weightResult, v[:]...) + } + } + return nil, nil +} + +//根据权重从列表获取元素 +//入参分别是抽取的数字列表、权重列表 +func GetByWeight(targetList []int, weightList []int) int { + //一开始就检查权重和对应的元素,长度是否一致 + if len(targetList) != len(weightList) { + panic("权重和目标列表元素数量不匹配") + } + weight := 0 + for _, v := range weightList { + weight += v + } + randNum := GetRandInt(1, weight) + sum := 0 + for index, v := range weightList { + sum += v + if sum >= randNum { + return targetList[index] + } + } + return 0 +} + +//根据权重不放回的抽取,出参是:抽到的道具、剩余没有抽的道具 +func GetAwardByWeightWithLeftAward(srcAwardList [][]int) ([]int, [][]int) { + //这边应该加一个数组的检查. + weightListCheck(srcAwardList) + + awardList := array.DeepCopyIntSlice2(srcAwardList) + + weight := 0 + award := make([]int, 0) + leftAwards := make([][]int, 0) + for _, v := range awardList { + weight += v[len(v)-1] + } + randNum := GetRandInt(1, weight) + sum := 0 + for index, v := range awardList { + sum += v[len(v)-1] + if sum >= randNum { + //如果获取到奖励则将当前获取的奖励扣除 + leftAwards = append(awardList[0:index], awardList[index+1:]...) + award = v[:len(v)-1] + return award, leftAwards + } + } + return award, leftAwards +} + +//根据权重不放回的抽取X个元素,直接返回这些元素 +// 入参:奖池、抽取数量,出参:获得的所有道具 +func GetCountAwardsFromPool(srcAwardPool [][]int, count int) [][]int { + awardPool := array.DeepCopyIntSlice2(srcAwardPool) + + if count > len(awardPool) { + panic("抽取数量不对") + } + var finalAwardList [][]int + var award []int + var leftAward = make([][]int, len(awardPool)) + copy(leftAward, awardPool) + + for i := 0; i < count; i++ { + award, leftAward = GetAwardByWeightWithLeftAward(leftAward) + finalAwardList = append(finalAwardList, award) + } + return finalAwardList +} + +//通过百分比的方式来获取对应的数组,也就是说权重的总值可能超过传入的百分比数,此时取的只是0-百分比数的范围内 +//所以这个方法可以按照概率取一个范围内的元素 +func GetAwardByPercentage(srcAwardList [][]int, fullPercent int) []int { + weightListCheck(srcAwardList) + if fullPercent <= 0 { + panic("抽取概率不能小于等于0") + } + + awardList := array.DeepCopyIntSlice2(srcAwardList) + + randNum := GetRandInt(1, fullPercent) + sum := 0 + for _, v := range awardList { + sum += v[len(v)-1] + if sum >= randNum { + result := make([]int, 0) + return append(result, v[:len(v)-1]...) + } + } + return []int{} +} + +func weightListCheck(awardList [][]int) { + for _, r := range awardList { + if len(r) == 0 { + panic("一维数组长度不能为0,必须存在权重") + } + } +} + +func InitRand() { + R = rand.New(rand.NewSource(time.Now().UnixNano())) +} + +func init() { + InitRand() +}