如何种子lodash随机数生成器?

huangapple go评论81阅读模式
英文:

How to seed lodash random number generator?

问题

如何使 lodash 的随机数生成器(rng)的种子可复制,以便于 shuffle 函数的随机选择是可重现的?

例如:

import _ from 'lodash'

console.log(_.shuffle([1,2,3,4]))

运行 #1 输出:[1,3,4,2]

运行 #2 输出:[3,2,1,4]

运行 #3 输出:[4,1,2,3]

结果总是不同的。

英文:

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.

答案1

得分: 1

lodash 在内部使用自己的 Math.random,但它与全局的 Math.random 是独立的,因此使用类似 seedrandom 这样的库来使 Math.random 可以生成随机种子是行不通的。

相反,我们需要使用 lodashrunInContext() 函数,该函数使用当前的全局状态而不是使用它自己隐藏的版本。结合一个可生成随机种子的 RNG(例如 seedrandom),我们可以使用以下方法来获取 lodash 的带种子的版本:

import _lodash from 'lodash'
import seedrandom from 'seedrandom'

// 使用给定的种子创建一个新的 lodash 实例
export const seedLodash = (seed: number | string) => {
    // 获取当前 Math.random() 函数的快照
    const orig = Math.random
    // 用带种子的随机数替换 Math.random
    seedrandom(seed, { global: true })
    // runInContext() 使用带种子的 Math.random 创建一个新的 lodash 实例
    // 上下文是全局 JavaScript 环境状态的快照,即 Math.random() 更新为 seedrandom 实例
    const lodash = _lodash.runInContext()
    // 恢复原始的 Math.random() 函数
    Math.random = orig
    // 返回带种子的 Math.random 的 lodash 实例
    return lodash
}

这将创建一个 RNG,替换 Math.random,创建一个引用修改后的 Math.random 的新的 lodash 实例,然后将 Math.random 替换为原始未修改(即未种子化)的版本。

如果您想同时为 lodashMath.random 生成随机种子,请在代码的顶部添加以下两行:

import _lodash from 'lodash'
import seedrandom from 'seedrandom'

seedrandom(seed, { global: true });
const _ = _lodash.runInContext();
// 像平常一样使用 lodash 和 Math.random...
英文:

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...

huangapple
  • 本文由 发表于 2023年7月17日 23:04:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76705788.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定