Better Randomization Support in JS

I've seen a few of these threads, but none that covers all the aspects of randomization I struggle with.
Randomization in JavaScript is very frustrating, and sometimes unusably slow (e.g. generating white noise or RGB noise). There is room for improvement here.

I usually find myself adding these functionalities:

  • Balanced random.
randomFloat = () => Math.random()*2 - 1;
  • Random range.
randomRange = ( start, end ) => start + Math.random() * (end-start);
  • Random integer.
randomInt = ( start, end ) =>
    parseInt( start + Math.random()*(end-start) );
  • Seeded randomization. (Mulberry32 is my concise habit here.)
seededRandom = seed =>
    ( t = ( seed += 0x6D2B79F5 ) ) => (
        t = Math.imul( t ^ t >>> 15, t | 1 ),
        t ^= t + Math.imul( t ^ t >>> 7, t | 61 ),
        ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296
  • Random array element selection.
randomArrayElement = array =>
    array[ parseInt( Math.random() * array.length ) ];
  • Random object value selection. (Very inefficient!)
randomObjectValue = ( object, keys = Object.keys( object ) ) =>
    object[ keys[ parseInt( Math.random() * keys.length ) ] ];

(I have similar problems for Set and Map that similarly require generating and throwing away an array with every single call.)

  • Filling a TypedArray with random data.
/* (Use WebGL or WASM. Too long to demo here.) */

But Most Crucially!
With iterator definitions, no standard interface exists for querying a "random" selection from the iterator's sequence.
(Obviously not all iterators could or should define a random-from-sequence selection interface, but in the cases where I need it, I have to avoid iterators completely. That requires tremendous foresight during planning, which makes it easier to simply avoid iterators from the start.)

Would it be possible to generally address JavaScript's problems with randomization?


Is my question too abstract? I could make a suggestion. Something like: 0, 42 ); //maybe returns 33

var a = new Set( [1,2,3,5] );
Random.entryFrom( a ); //maybe returns 2

var b = { "x":11, "y":22, "z":33 }
Random.entryFrom( b ); //maybe returns ["z",33]

Random could handle arrays, strings, shuffling, statistical distributions... I don't know. Whatever makes most sense and would be used most.
For iterators, there might be a [@@random]() or [@@randomSkip]() symbol or some such that Random.entryFrom() could attempt to call, perhaps?

There is Crypto.getRandomValues() - Web APIs | MDN for this particular one.

Don't use parseInt on numbers. It is meant to parse strings containing digits, and using it on numbers is very inefficient and slow. Use Math.floor for the same effect:

randomInt = ( start, end ) =>
    Math.floor( start + Math.random()*(end-start) );
randomArrayElement = array =>
    array[ Math.floor( Math.random() * array.length ) ];

It's easy to see why: iterators do not have a known length. The best you could do is some kind of geometric progression of probabilities, and still there's always some probability to get no value if choosing a value behind the end of the iterator (100% for an empty iterator).

If you do know the expected length of the generated sequence, and want to choose one element with equal probability, you can just do




That does not work for floats, and offers no control. If there were helpful ways of addressing the majority of use cases, I would not find randomization "frustrating".

Please do not nitpick the demo code. I am saying that none of this should be implemented in user JS at all.

You misunderstood the iterator problem. I do not want an algorithm that messes with my iterators, I want an interface that lets me implement my own algorithm.

Imagine if arrays or strings only allowed linear access. How useless would they be? Right now in JS, Objects, Sets, Maps, and Iterators all have that exact limitation.

for in/of is the only syntax that exists for accessing the elements of an Object, Set, Map, or Iterator. Selecting a random element requires allocating memory for a new array, copying values to it, accessing a random element of the array, then disposing of the array (or installing a mutation watcher on every operation performed on the target to dispose of the array if the target changes). It's inefficient.