How can I seed the lodash rng so that the random choices for the shuffle function are reproducible?
E.g.
import _ from 'lodash'
console.log(_.shuffle([1,2,3,4]))
Run #1 output: [1,3,4,2]
Run #2 output: [3,2,1,4]
Run #3 output: [4,1,2,3]
The result is always different.
lodash
uses its own Math.random
under the hood, but it is independent from the global Math.random
, so using a library like seedrandom
to make Math.random
seedable does not work.
Instead, we have to make use of lodash
's runInContext()
function which uses the current global state instead of using it's own hidden-away version. Combining this with a seedable rng like seedrandom
we can use the following to get a seeded version of lodash
:
import _lodash from 'lodash'
import seedrandom from 'seedrandom'
// create a new lodash instance with the given seed
export const seedLodash = (seed: number | string) => {
// take a snapshot of the current Math.random() fn
const orig = Math.random
// replace Math.random with the seeded random
seedrandom(seed, { global: true })
// runInContext() creates a new lodash instance using the seeded Math.random()
// the context is a snapshot of the state of the global javascript environment, i.e. Math.random() updated to the seedrandom instance
const lodash = _lodash.runInContext()
// restore the original Math.random() fn
Math.random = orig
// return the lodash instance with the seeded Math.random()
return lodash
}
This creates an rng which replaces Math.random
, makes a new lodash
instance referencing the modified Math.random
, then replaces Math.random
with the original unmodified (i.e. unseeded) version.
If you want to seed both lodash
and Math.random
simply add these two lines at the top of your code:
import _lodash from 'lodash'
import seedrandom from 'seedrandom'
seedrandom(seed, { global: true });
const _ = _lodash.runInContext();
// use lodash and Math.random as normal...