fictional
Version:
Generate fake data deterministically from a given input
110 lines (86 loc) • 2.28 kB
JavaScript
var hash = require('./hash')
var resolve = require('./utils/resolve')
var hash2 = hash.hash2
var EPS = 0.0001
function oneOfWeighted(a, b) {
return b != null ? oneOfWeightedMain(a, b) : oneOfWeightedCurried(a)
}
function oneOfWeightedMain(input, samples) {
samples = parseSamples(samples)
var id = hash2(input, 'oneOfWeighted')
var prob = (id % 1000000) / 1000000
var cumulative = 0
for (var i = 0; i < samples.length; i++) {
cumulative += samples[i][0]
if (prob < cumulative) {
return resolve(id, samples[i][1])
}
}
throw new Error(
'Unexpectedly reached end of oneOfWeighted() unresolved. If you see this please file a bug.'
)
}
function oneOfWeightedCurried(samples) {
samples = parseSamples(samples)
return function oneOfWeightedCurriedFn(input) {
return oneOfWeighted(input, samples)
}
}
function parseSamples(samples) {
if (samples.__parsed) {
return samples
}
var samplesLen = samples.length
var assignedPs = getAssignedPs(samples)
var sumAssignedPs = assignedPs.reduce(add, 0)
var assignedPsLen = assignedPs.length
if (!samplesLen) {
throw new Error('Empty samples given to oneOfWeighted')
}
if (sumAssignedPs > 1 + EPS) {
throw new Error(
'Assigned probabilities add up more than 1: ' + JSON.stringify(assignedPs)
)
} else if (samplesLen === assignedPsLen && sumAssignedPs < 1 - EPS) {
throw new Error(
'All items were assigned probabilities, yet the probabilities add up to less than 1: ' +
JSON.stringify(assignedPs)
)
}
var defaultP = (1 - sumAssignedPs) / (samplesLen - assignedPsLen)
return ensurePs(samples, defaultP)
}
function ensurePs(samples, defaultP) {
var result = []
var i = -1
var n = samples.length
var sample
var p
while (++i < n) {
sample = samples[i]
p = sample[0]
if (typeof p !== 'number') {
p = defaultP
}
result.push([p, sample[1]])
}
result.__parsed = true
return result
}
function getAssignedPs(samples) {
var i = -1
var n = samples.length
var result = []
var p
while (++i < n) {
p = samples[i][0]
if (typeof p === 'number') {
result.push(p)
}
}
return result
}
function add(a, b) {
return a + b
}
module.exports = oneOfWeighted