个人记录 一个简单的权重抽奖方法 最近一个需求,需要从配置不同权重的数据做一个多次并且不重复的抽奖 大概是这样
| id | name | weight |
|---|---|---|
| 1 | 物品1 | 5 |
| 2 | 物品2 | 3 |
| 3 | 物品3 | 2 |
| 4 | 物品4 | 2 |
| 5 | 物品5 | 1 |
一开始想法是 计算出权重总和 记录一个id对应每个奖励的最大权重值的 map(id->maxWeight),然后从权重总和随机一个权重数出来,属于哪个区间即抽到哪个奖励. 代码如下:
func DoWeight(props []Prop) int {
var weightSum int //权重总和
var idMap = make(map[int]int)
for _, prop := range props {
var maxWeight int
weightSum += prop.weight
maxWeight = weightSum
idMap[prop.id] = maxWeight
}
rand.Seed(time.Now().UnixNano())
r := RandInt(1, int(weightSum)) - 1
for id, maxW := range idMap {
if r < maxW {
return id
}
}
return 0
}
func RandInt(min, max int) int {
if min >= max || min == 0 || max == 0 {
return max
}
return rand.Intn(max-min) + min
}
但是这个方法并不适用于多次并且不重复的抽奖,基于这个方法修改的话感觉会很复杂,需要清除已抽到的物品重新随机,于是就做了个切片来处理,虽然感觉也不是很好,勉强能用吧... 代码如下:
func DoMutiWeight(props []Prop, count int) []int32 {
var ids = make([]int, 0) // [1,1,1,1,1,2,2,2,3,3,4,4,5]
var weightSum int //权重总和
for _, prop := range props {
weightSum += prop.weight
for i := 0; i < int(prop.weight); i++ {
ids = append(ids, prop.id)
}
}
resultIds := WeightedRandomIndex(ids, count)
return resultIds
}
func WeightedRandomIndex(ids []int, count int) []int {
rand.Seed(time.Now().UnixNano())
var tmp *[]int
tmp = &ids
var res []int
for i := 0; i < count; i++ {
l := len(*(tmp))
r := RandInt(1, l) - 1
a := (*tmp)[r]
res = append(res, a)
for j := l - 1; j >= 0; j-- {
if (*tmp)[j] == a {
(*tmp) = append((*tmp)[:j], (*tmp)[j+1:]...) //ps:go的切片删除还是很不习惯。。。
}
}
}
return res
}
刚接触go不久, 当时写完这个方法总感觉怪怪的, 但是有没有想到更好的方法,由于工期问题也没有多考虑了,能实现就好。。。 还请看到的大佬勿喷, 能给我一些建议更好 ,在此感谢。