但是我在这里基本上要做的是获取一系列数字(数字数组),然后随机选择其中一个数字,而不重复已经选择的数字;
getRandomInt 函数是一个好的开始 -
const getRandomInt = (min = 0, max = 0) =>
Math.floor(Math.random() * (max - min)) + min
让我们创建一个函数来生成一个数字范围 -
const makeRange = (min = 0, max = 0) =>
min > max
? []
: [ min, ...makeRange(min + 1, max) ]
我们不必循环查找下一个随机值。我们可以swap 数组中的元素来有效地创建随机序列。这种技术被称为Fisher-Yates shuffle -
const getUniqueRandom = (min = 0, max = 0) =>
{ const r = makeRange(min, max)
const next = (i = 0) =>
{ if (i >= r.length) return undefined
swap(r, i, getRandomInt(i, r.length))
return r[i]
}
let i = 0
const rand = () =>
next(i++)
return rand
}
最后我们需要编写swap函数-
const swap = (a = [], i = 0, j = 0) =>
[a[j], a[i]] = [a[i], a[j]]
现在是它的工作原理-
const rand = getUniqueRandom(3,7)
console.log(rand()) // 4
console.log(rand()) // 7
继续调用它以获取其余值。当没有可能的唯一输出时,它返回undefined -
console.log(rand()) // 3
console.log(rand()) // 6
console.log(rand()) // 5
console.log(rand()) // undefined
展开下面的 sn-p 以在您自己的浏览器中验证输出。按Run多次查看随机输出 -
const getRandomInt = (min = 0, max = 0) =>
Math.floor(Math.random() * (max - min)) + min
const makeRange = (min = 0, max = 0) =>
min > max
? []
: [ min, ...makeRange(min + 1, max) ]
const swap = (a = [], i = 0, j = 0) =>
[a[j], a[i]] = [a[i], a[j]]
const getUniqueRandom = (min, max) =>
{ const r = makeRange(min, max)
const next = (i = 0) =>
{ if (i >= r.length)
return undefined
swap(r, i, getRandomInt(i, r.length))
return r[i]
}
let i = 0
const rand = () =>
next(i++)
return rand
}
const rand = getUniqueRandom(3,7)
console.log(rand()) // 4
console.log(rand()) // 7
console.log(rand()) // 3
console.log(rand()) // 6
console.log(rand()) // 5
console.log(rand()) // undefined
发电机
上面rand 演示的是某种生成器。现代 JavaScript 原生支持Generators,让我们可以方便地编写这个程序。您可能听说过他们用其他语言称为coroutines。
这是一个非常简单的生成器,我们可以将其用于makeRange。注意使用yield 而不是return -
const makeRange = function* (min = 0, max = 0)
{ while (min <= max)
yield min++
}
这是对getUniqueRandom 的重写。我们可以使用Array.from 收集来自makeRange(...) 的所有值 -
const getUniqueRandom = function* (min, max)
{ const r =
Array.from(makeRange(min, max))
for (let i = 0; i < r.length; i++)
{ swap(r, i, getRandomInt(i, r.length))
yield r[i]
}
}
逐一获取唯一的随机数 -
const rand = getUniqueRandom(3,7)
console.log(rand.next()) // { value: 7, done: false }
console.log(rand.next()) // { value: 3, done: false }
和以前一样,继续调用以获取下一个唯一随机数。当没有更多结果时,我们会看到 value: undefined 和 done: true -
console.log(rand.next()) // { value: 6, done: false }
console.log(rand.next()) // { value: 5, done: false }
console.log(rand.next()) // { value: 4, done: false }
console.log(rand.next()) // { value: undefined, done: true }
就像我们对 makeRange 所做的那样,如果我们想要立即获得所有结果,我们可以简单地使用 Array.from -
console.log(Array.from(getUniqueRandom(3, 7)))
// [ 6, 3, 4, 5, 7 ]
展开下面的 sn-p 以在您自己的浏览器中验证输出。按Run多次查看随机输出 -
const getRandomInt = (min = 0, max = 0) =>
Math.floor(Math.random() * (max - min)) + min
const swap = (a = [], i = 0, j = 0) =>
[a[j], a[i]] = [a[i], a[j]]
const makeRange = function* (min = 0, max = 0)
{ while (min <= max)
yield min++
}
const getUniqueRandom = function* (min, max)
{ const r =
Array.from(makeRange(min, max))
for (let i = 0; i < r.length; i++)
{ swap(r, i, getRandomInt(i, r.length))
yield r[i]
}
}
const rand = getUniqueRandom(3,7)
console.log(rand.next()) // { value: 7, done: false }
console.log(rand.next()) // { value: 3, done: false }
console.log(rand.next()) // { value: 6, done: false }
console.log(rand.next()) // { value: 5, done: false }
console.log(rand.next()) // { value: 4, done: false }
console.log(rand.next()) // { value: undefined, done: true }
console.log(Array.from(getUniqueRandom(3, 7)))
// [ 6, 3, 4, 5, 7 ]