1
0
Fork 0

added an new package: weightrandom

this lets developers randomly choose one item
Dieser Commit ist enthalten in:
Sebastian Tobie 2023-03-28 23:32:33 +02:00
Ursprung 926788a128
Commit 82a722a4e5
5 geänderte Dateien mit 175 neuen und 0 gelöschten Zeilen

6
go.sum
Datei anzeigen

@ -5,12 +5,18 @@ github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrt
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

56
weightedrandom/common.go Normale Datei
Datei anzeigen

@ -0,0 +1,56 @@
package weightedrandom
import (
"crypto/rand"
"math"
"math/big"
)
type ordered interface {
int | int8 | int16 | int32 | int64 |
uint | uint8 | uint16 | uint32 | uint64 |
float32 | float64 |
string
}
// RandomFunc is the Type for random values required for this
type RandomFunc func(int) int
// AdjustFunc is the function that returns an adjusted value for the weighting
type AdjustFunc func(itemweight int, totalWeight int) int
// AccessModifier is executed before an item is returned and returns the modified weight of an item.
type AccessModifier func(oldweight int) int
// RandInt is the standard function for returning random numbers. It returns an random number between 0 and max
func RandInt(max int) int {
out, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
if err != nil {
panic(err)
}
return int(out.Int64())
}
// StandardAdjustFunc returns the normal weight for the adjustment
func StandardAdjustFunc(standardweight, _ int) int {
return standardweight
}
// ReverseWeightAdjustFunc returns the value relative to the total weight
func ReverseWeightAdjustFunc(weight, totalWeight int) int {
return totalWeight / weight
}
// Addone adds one until the max value is reached, after that it returns only the max value
func Addone(oldweight int) int {
if oldweight != math.MaxInt {
return oldweight + 1
}
return oldweight
}
type weightitem[T any] struct {
weight int
adjusted int
value T
}

2
weightedrandom/doc.go Normale Datei
Datei anzeigen

@ -0,0 +1,2 @@
// Package weightedrandom provides multiple weighted random lists
package weightedrandom

11
weightedrandom/new.go Normale Datei
Datei anzeigen

@ -0,0 +1,11 @@
package weightedrandom
// New returns an new instance of WeightRandom
func New[T any](af AdjustFunc, rf RandomFunc, acf AccessModifier) *WeightRandom[T] {
return &WeightRandom[T]{
data: []*weightitem[T]{},
weightFunc: af,
randomFunc: rf,
accessfunc: acf,
}
}

Datei anzeigen

@ -0,0 +1,100 @@
package weightedrandom
import "sort"
var (
_ sort.Interface = &wflist[int]{}
)
type wflist[T any] []*weightitem[T]
func (wfl wflist[T]) Less(i, j int) bool {
return wfl[i].adjusted < wfl[j].adjusted
}
func (wfl wflist[T]) Len() int {
return len(wfl)
}
func (wfl wflist[T]) Swap(i, j int) {
wfl[i], wfl[j] = wfl[j], wfl[i]
}
// WeightRandom is the Type for an weighted random list
type WeightRandom[T any] struct {
data wflist[T]
weightFunc AdjustFunc
randomFunc RandomFunc
sorted bool
totalWeight int
adjustedWeight int
sorti sort.Interface
accessfunc AccessModifier
}
func (wr *WeightRandom[T]) reweight() {
wr.updatetotal()
for _, item := range wr.data {
item.adjusted = wr.weightFunc(item.weight, wr.totalWeight)
}
}
func (wr *WeightRandom[T]) sort() {
if wr.sorted {
return
}
if wr.sorti == nil {
wr.sorti = sort.Reverse(&wr.data)
}
wr.reweight()
sort.Stable(wr.sorti)
wr.sorted = true
}
func (wr *WeightRandom[T]) updatetotal() {
newtotal := 0
newadjusted := 0
for _, item := range wr.data {
newtotal += item.weight
newadjusted += item.adjusted
}
wr.adjustedWeight = newadjusted
wr.totalWeight = newtotal
}
// AddElement adds an single Element to the list
func (wr *WeightRandom[T]) AddElement(item T, weight int) {
wr.sorted = false
wr.totalWeight += weight
wr.data = append(wr.data, &weightitem[T]{weight: weight, value: item})
}
// AddElements adds an list of elements to the list
func (wr *WeightRandom[T]) AddElements(weight int, items ...T) {
for _, item := range items {
wr.AddElement(item, weight)
}
wr.reweight()
wr.sort()
}
// Get returns an random value of the list of items or the null value of the type in case no element was added
func (wr *WeightRandom[T]) Get() (t T) {
if !wr.sorted {
wr.reweight()
wr.sort()
}
pos := wr.randomFunc(wr.data.Len())
for _, item := range wr.data {
pos -= item.adjusted
if pos <= 0 {
if wr.accessfunc != nil {
wr.sorted = false
item.weight = wr.accessfunc(item.weight)
}
return item.value
}
}
return
}