记录 一个简单的golang权重抽奖方法

806 阅读1分钟

个人记录 一个简单的权重抽奖方法 最近一个需求,需要从配置不同权重的数据做一个多次并且不重复的抽奖 大概是这样

idnameweight
1物品15
2物品23
3物品32
4物品42
5物品51

一开始想法是 计算出权重总和 记录一个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不久, 当时写完这个方法总感觉怪怪的, 但是有没有想到更好的方法,由于工期问题也没有多考虑了,能实现就好。。。 还请看到的大佬勿喷, 能给我一些建议更好 ,在此感谢。