我试图理解递归的概念,并想在我的代码(getUniqueInt函数)中使用它:
var getRandomInt = function (min, max) {
return Math.floor(Math.random() * (max - min)) + min;
};
var getChosenNumbers = function (min, max) {
var chosenNumbers = [];
for (var k = min; k <= max; k++) {
chosenNumbers.push(k);
}
return chosenNumbers;
};
var arrayOfNumbers = getChosenNumbers(1, 8);
var getUniqueInt = function (min, max) {
var uniqueNumber;
var randomNumber = getRandomInt(min, max);
if (arrayOfNumbers.indexOf(randomNumber) !== -1) {
uniqueNumber = randomNumber;
arrayOfNumbers.splice(arrayOfNumbers.indexOf(uniqueNumber), 1);
} else {
uniqueNumber = getUniqueInt(min, max);
}
return uniqueNumber;
};
但是我最终得到了这个: 未捕获的RangeError:超出了最大调用堆栈大小
我在做什么错?我的代码(我的意思是递归部分)有意义吗?还是完全错误?
答案 0 :(得分:1)
抱歉,您的代码没有意义,这就是原因
设置最小值= 0,最大值= 10
getRandomInt
返回0-10之间的随机整数
getChosenNumbers
从0-10返回int数组,表示[1、2、3、4、5、6、7、8、9、10]
arrayOfNumbers
现在是[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
getUniqueInt
根本无法获得唯一性,因为getRandomInt
的所有可能随机值已经在getChosenNumbers
那就是为什么
else {
uniqueNumber = getUniqueInt(min, max);
}
被称为无限次,因为
arrayOfNumbers.indexOf(randomNumber) !== -1
永远不是真的
答案 1 :(得分:1)
但是我在这里基本上要做的是获取一个数字范围(数字数组),然后在不重复已经选择的数字的情况下随机选择这些数字之一;
您的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
展开以下代码段,以在您自己的浏览器中验证输出。多次按 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
的重写。我们可以使用makeRange(...)
-
Array.from
收集所有值
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 ]
展开以下代码段,以在您自己的浏览器中验证输出。多次按 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 ]