英文:
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
可以生成随机种子是行不通的。
相反,我们需要使用 lodash
的 runInContext()
函数,该函数使用当前的全局状态而不是使用它自己隐藏的版本。结合一个可生成随机种子的 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
替换为原始未修改(即未种子化)的版本。
如果您想同时为 lodash
和 Math.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...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论