forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/brianvoe/gofakeit/v6/weighted.go

175 lines
2.8 KiB
Go
Raw Normal View History

2024-04-26 19:30:35 +00:00
package gofakeit
import (
"errors"
"math/rand"
)
// Weighted will take in an array of options and weights and return a random selection based upon its indexed weight
2024-04-26 19:30:35 +00:00
func Weighted(options []any, weights []float32) (any, error) {
2024-04-26 19:30:35 +00:00
return weighted(globalFaker.Rand, options, weights)
2024-04-26 19:30:35 +00:00
}
// Weighted will take in an array of options and weights and return a random selection based upon its indexed weight
2024-04-26 19:30:35 +00:00
func (f *Faker) Weighted(options []any, weights []float32) (any, error) {
2024-04-26 19:30:35 +00:00
return weighted(f.Rand, options, weights)
2024-04-26 19:30:35 +00:00
}
// Weighted will take in an array of options and weights and return a random selection based upon its indexed weight
2024-04-26 19:30:35 +00:00
func weighted(r *rand.Rand, options []any, weights []float32) (any, error) {
2024-04-26 19:30:35 +00:00
ol := len(options)
2024-04-26 19:30:35 +00:00
wl := len(weights)
// If options length is 1 just return it back
2024-04-26 19:30:35 +00:00
if ol == 1 {
2024-04-26 19:30:35 +00:00
return options[0], nil
2024-04-26 19:30:35 +00:00
}
// Make sure they are passing in options
2024-04-26 19:30:35 +00:00
if ol == 0 {
2024-04-26 19:30:35 +00:00
return nil, errors.New("didnt pass options")
2024-04-26 19:30:35 +00:00
}
// Make sure they are passing in weights
2024-04-26 19:30:35 +00:00
if wl == 0 {
2024-04-26 19:30:35 +00:00
return nil, errors.New("didnt pass weights")
2024-04-26 19:30:35 +00:00
}
// Make sure they are passing in the same length
2024-04-26 19:30:35 +00:00
if ol != wl {
2024-04-26 19:30:35 +00:00
return nil, errors.New("options and weights need to be the same length")
2024-04-26 19:30:35 +00:00
}
// Compute the discrete cumulative density from the sum of the weights
2024-04-26 19:30:35 +00:00
cdf := make([]float32, wl)
2024-04-26 19:30:35 +00:00
var sumOfWeights float32 = 0.0
2024-04-26 19:30:35 +00:00
for i, weight := range weights {
2024-04-26 19:30:35 +00:00
if i > 0 {
2024-04-26 19:30:35 +00:00
cdf[i] = cdf[i-1] + weight
2024-04-26 19:30:35 +00:00
sumOfWeights += weight
2024-04-26 19:30:35 +00:00
continue
2024-04-26 19:30:35 +00:00
}
cdf[i] = weight
2024-04-26 19:30:35 +00:00
sumOfWeights += weight
2024-04-26 19:30:35 +00:00
}
// Get rand value from a multple of sumOfWeights
2024-04-26 19:30:35 +00:00
randSumOfWeights := r.Float32() * sumOfWeights
var l int = 0
2024-04-26 19:30:35 +00:00
var h int = wl - 1
2024-04-26 19:30:35 +00:00
for l <= h {
2024-04-26 19:30:35 +00:00
m := l + (h-l)/2
2024-04-26 19:30:35 +00:00
if randSumOfWeights <= cdf[m] {
2024-04-26 19:30:35 +00:00
if m == 0 || (m > 0 && randSumOfWeights > cdf[m-1]) {
2024-04-26 19:30:35 +00:00
return options[m], nil
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
h = m - 1
2024-04-26 19:30:35 +00:00
} else {
2024-04-26 19:30:35 +00:00
l = m + 1
2024-04-26 19:30:35 +00:00
}
2024-04-26 19:30:35 +00:00
}
return nil, errors.New("end of function")
2024-04-26 19:30:35 +00:00
}
func addWeightedLookup() {
2024-04-26 19:30:35 +00:00
AddFuncLookup("weighted", Info{
Display: "Weighted",
Category: "misc",
2024-04-26 19:30:35 +00:00
Description: "Randomly select a given option based upon an equal amount of weights",
Example: "[hello, 2, 6.9],[1, 2, 3] => 6.9",
Output: "any",
2024-04-26 19:30:35 +00:00
Params: []Param{
2024-04-26 19:30:35 +00:00
{Field: "options", Display: "Options", Type: "[]string", Description: "Array of any values"},
2024-04-26 19:30:35 +00:00
{Field: "weights", Display: "Weights", Type: "[]float", Description: "Array of weights"},
},
2024-04-26 19:30:35 +00:00
Generate: func(r *rand.Rand, m *MapParams, info *Info) (any, error) {
2024-04-26 19:30:35 +00:00
options, err := info.GetStringArray(m, "options")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
weights, err := info.GetFloat32Array(m, "weights")
2024-04-26 19:30:35 +00:00
if err != nil {
2024-04-26 19:30:35 +00:00
return nil, err
2024-04-26 19:30:35 +00:00
}
optionsInterface := make([]any, len(options))
2024-04-26 19:30:35 +00:00
for i, o := range options {
2024-04-26 19:30:35 +00:00
optionsInterface[i] = o
2024-04-26 19:30:35 +00:00
}
return weighted(r, optionsInterface, weights)
2024-04-26 19:30:35 +00:00
},
})
2024-04-26 19:30:35 +00:00
}