rand.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package otherutils
  2. import (
  3. "errors"
  4. "math/rand"
  5. )
  6. func init() {
  7. // rand.Seed(time.Now().UnixNano())
  8. }
  9. // RandInterval 随机1个数
  10. func RandInterval(b1, b2 int64) int64 {
  11. min, max := normalizeRange(b1, b2)
  12. return min + rand.Int63n(max-min+1)
  13. }
  14. // RandInterval64 随机1个数
  15. func RandInterval64(b1, b2 int64) int64 {
  16. min, max := normalizeRange64(b1, b2)
  17. return min + rand.Int63n(max-min+1)
  18. }
  19. func normalizeRange64(b1, b2 int64) (min, max int64) {
  20. if b1 < b2 {
  21. return b1, b2
  22. }
  23. return b2, b1
  24. }
  25. // RandIntervalN 随机生成n个范围在[b1, b2]之间的唯一整数
  26. // 使用Fisher-Yates洗牌算法
  27. func RandIntervalN(b1, b2 int64, n int64) []int64 {
  28. min, max := normalizeRange(b1, b2)
  29. rangeSize := max - min + 1
  30. n = limitCount(n, int64(rangeSize))
  31. if n == 1 {
  32. return []int64{min + rand.Int63n(max-min+1)}
  33. }
  34. return generateUniqueRandomNumbers(min, max, n)
  35. }
  36. func normalizeRange(b1, b2 int64) (min, max int64) {
  37. if b1 < b2 {
  38. return b1, b2
  39. }
  40. return b2, b1
  41. }
  42. func limitCount(n int64, rangeSize int64) int64 {
  43. if n > rangeSize {
  44. return rangeSize
  45. }
  46. return n
  47. }
  48. func generateUniqueRandomNumbers(min, max int64, n int64) []int64 {
  49. result := make([]int64, n)
  50. usedNumbers := make(map[int64]int64)
  51. rangeSize := max - min + 1
  52. for i := int64(0); i < n; i++ {
  53. randomValue := min + rand.Int63n(rangeSize)
  54. if replacementValue, exists := usedNumbers[randomValue]; exists {
  55. result[i] = replacementValue
  56. } else {
  57. result[i] = randomValue
  58. }
  59. lastValue := max - i
  60. if randomValue != lastValue {
  61. if replacementValue, exists := usedNumbers[lastValue]; exists {
  62. usedNumbers[randomValue] = replacementValue
  63. } else {
  64. usedNumbers[randomValue] = lastValue
  65. }
  66. }
  67. rangeSize--
  68. }
  69. return result
  70. }
  71. type Number interface {
  72. int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64
  73. }
  74. // RandOneNum 随机一个数字
  75. func RandOneNum[T Number](min, max T) T {
  76. if min == max {
  77. return min
  78. }
  79. if min > max {
  80. min, max = max, min
  81. }
  82. var result T
  83. switch any(min).(type) {
  84. case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
  85. result = T(rand.Int63n(int64(max-min)) + int64(min))
  86. case float32, float64:
  87. result = T(rand.Float64()*(float64(max)-float64(min)) + float64(min))
  88. default:
  89. panic("invalid type")
  90. }
  91. return result
  92. }
  93. // RandChoiceByWeighted 根据权重选取一个元素 [[id,weight]]
  94. func RandChoiceByWeighted(items [][]int64) int64 {
  95. var totalWeight int64
  96. for _, item := range items {
  97. totalWeight += item[1]
  98. }
  99. if totalWeight <= 0 {
  100. return -1
  101. }
  102. // 生成一个0到总权重之间的随机数
  103. randomNumber := rand.Int63n(totalWeight) + 1
  104. // 累积权重,直到累积权重超过随机数
  105. var cumulativeWeight int64
  106. for _, item := range items {
  107. cumulativeWeight += item[1]
  108. if randomNumber <= cumulativeWeight {
  109. return item[0]
  110. }
  111. }
  112. // 如果没有找到(理论上不会发生),返回0
  113. return -1
  114. }
  115. // type WeightedItem interface {
  116. // GetWeight() int64
  117. // }
  118. type WeightedTable[T any] struct {
  119. items []T
  120. totalWeight int64
  121. getWeight func(T) int64
  122. }
  123. func SetWeightedTable[T any](items []T, getWeight func(T) int64) *WeightedTable[T] {
  124. var totalWeight int64
  125. for _, item := range items {
  126. totalWeight += getWeight(item) //item.GetWeight()
  127. }
  128. return &WeightedTable[T]{
  129. items: items,
  130. totalWeight: totalWeight,
  131. getWeight: getWeight,
  132. }
  133. }
  134. func (rt *WeightedTable[T]) RandOneItem(reCalcWeight bool) (val T, err error) {
  135. var item T
  136. if reCalcWeight {
  137. var totalWeight int64
  138. for _, item := range rt.items {
  139. totalWeight += rt.getWeight(item)
  140. }
  141. rt.totalWeight = totalWeight
  142. }
  143. if rt.totalWeight <= 0 {
  144. return item, errors.New("total weight is zero")
  145. }
  146. // 生成一个0到总权重之间的随机数
  147. randomNumber := rand.Int63n(rt.totalWeight) + 1
  148. // 累积权重,直到累积权重超过随机数
  149. var cumulativeWeight int64
  150. for _, item := range rt.items {
  151. cumulativeWeight += rt.getWeight(item)
  152. if randomNumber <= cumulativeWeight {
  153. return item, nil
  154. }
  155. }
  156. // 如果没有找到(理论上不会发生),返回0
  157. return item, errors.New("not found")
  158. }