UNPKG

pandemonium

Version:

Typical random-related functions for JavaScript.

101 lines (79 loc) 2.23 kB
/** * Pandemonium Reservoir Sample * ============================= * * Reservoir sampling function. * * [Reference]: * https://en.wikipedia.org/wiki/Reservoir_sampling#Simple_algorithm */ var createRandomIndex = require('./random-index.js').createRandomIndex; /** * Helper class. */ function ReservoirSampler(k, rng) { if (!rng) rng = Math.random; this.randomIndex = createRandomIndex(rng); this.k = k; this.size = 0; this.sample = new Array(k); this.done = false; } ReservoirSampler.prototype.process = function (item) { if (this.done) { throw new Error( 'pandemonium/ReservoirSampler: this sampler has returned its result and cannot be used anymore.' ); } if (this.size < this.k) { this.sample[this.size++] = item; return; } var j = this.randomIndex(this.size); if (j < this.k) this.sample[j] = item; this.size++; }; ReservoirSampler.prototype.end = function () { this.done = true; if (this.size < this.k) this.sample.length = this.size; return this.sample; }; /** * Creating a function returning a sample of size n using the provided RNG. * * @param {function} rng - The RNG to use. * @return {function} - The created function. */ function createReservoirSample(rng) { var customRandomIndex = createRandomIndex(rng); /** * Function returning sample of size n from array. * * @param {number} k - Size of the sample. * @param {array|number} sequence - Target sequence or its length. * @return {array} - The random sample. */ return function (k, sequence) { var n = sequence.length; // Sample size gte sequence's length if (k >= n) return sequence.slice(); var sample = new Array(k); var i, j; for (i = 0; i < k; i++) sample[i] = sequence[i]; for (; i < n; i++) { j = customRandomIndex(i); if (j < k) sample[j] = sequence[i]; } return sample; }; } /** * Default reservoir sample using `Math.random`. */ var reservoirSample = createReservoirSample(Math.random); /** * Exporting. */ reservoirSample.createReservoirSample = createReservoirSample; reservoirSample.ReservoirSampler = ReservoirSampler; module.exports = reservoirSample;