Skip to content

Commit

Permalink
feat(random): add randomID() & weightedRandom()
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Feb 12, 2019
1 parent b0b41f7 commit f719724
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/random/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ export * from "./system";
export * from "./xorshift128";
export * from "./xorwow";
export * from "./xsadd";

export * from "./random-id";
export * from "./weighted-random";
28 changes: 28 additions & 0 deletions packages/random/src/random-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { IRandom } from "./api";
import { SYSTEM } from "./system";

/**
* Generates and returns a random string of `len` characters (default
* 4), plus optional given `prefix` and using only provided `syms`
* characters (default lowercase a-z).
*
* ```
* randomID()
* "qgdt"
*
* randomID(8, "id-", "0123456789ABCDEF")
* "id-94EF6E1A"
* ```
*
* @param len
* @param prefix
* @param syms
* @param rnd
*/
export const randomID =
(len = 4, prefix = "", syms = "abcdefghijklmnopqrstuvwxyz", rnd: IRandom = SYSTEM) => {
for (const n = syms.length; --len >= 0;) {
prefix += syms[rnd.float(n) | 0];
}
return prefix;
};
40 changes: 40 additions & 0 deletions packages/random/src/weighted-random.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { IRandom } from "./api";
import { SYSTEM } from "./system";

/**
* Returns a no-arg function which produces a random choice of given
* weighted `choices` and using given `IRandom` instance (default:
* `SYSTEM`). If `weights` are given, it must be the same size as
* `choices`. If omitted, each choice will have same probability.
*
* https://www.electricmonk.nl/log/2009/12/23/weighted-random-distribution/
*
* @param choices
* @param weights
*/
export const weightedRandom = <T>(
choices: Array<T>,
weights?: ArrayLike<number>,
rnd: IRandom = SYSTEM
) => {
const opts = choices.map(
weights ?
(x, i) => <[T, number]>[x, weights[i]] :
(x) => <[T, number]>[x, 1]
).sort((a, b) => b[1] - a[1]);
const n = choices.length;
let total = 0, i: number, r: number, sum: number;
for (i = 0; i < n; i++) {
total += opts[i][1];
}
return () => {
r = rnd.float(total);
sum = total;
for (i = 0; i < n; i++) {
sum -= opts[i][1];
if (sum <= r) {
return opts[i][0];
}
}
};
};

0 comments on commit f719724

Please sign in to comment.