如何使用Math.random()从题库随机抽取指定数量题目?
嘿,我明白你要做的事儿了——从100道题里随机抽5道,每次测验内容都不一样对吧?之前搞混了Math.log()和Math.random()也很正常,毕竟这俩确实搭不上边~下面给你几个靠谱的JavaScript实现方案,按需选就行:
方案1:Fisher-Yates洗牌法(推荐)
这是生成无偏随机序列的经典方法,先把整个题目数组打乱,再取前5道,完美满足“每次测验内容不同”的需求,效率也拉满,100道题完全没压力。
// 假设你有100道题的数组,结构可以自定义(比如包含题干、选项的对象) const allQuestions = [ { id: 1, text: "题目1内容", options: ["A", "B", "C", "D"] }, { id: 2, text: "题目2内容", options: ["A", "B", "C", "D"] }, // ... 剩下98道题 ]; function getRandomQuestions(questions, count) { // 先复制原数组,避免修改原始题目列表 const shuffled = [...questions]; let currentIndex = shuffled.length, randomIndex; // Fisher-Yates洗牌核心逻辑 while (currentIndex > 0) { // 生成0到当前索引之间的随机整数 randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; // 交换当前元素和随机选中的元素 [shuffled[currentIndex], shuffled[randomIndex]] = [shuffled[randomIndex], shuffled[currentIndex]]; } // 返回前count道题 return shuffled.slice(0, count); } // 调用方法,获取5道随机题 const quizQuestions = getRandomQuestions(allQuestions, 5); console.log(quizQuestions);
为啥推荐这个方法?
- 完全无偏:每道题被选中的概率完全相等,不会出现某些题总被抽到的情况
- 不污染原数组:通过
[...questions]复制了一份,原始的题目列表不会被打乱 - 效率高:时间复杂度是O(n),100道题眨眼就处理完
方案2:无洗牌的随机选取(适合不想打乱数组的场景)
如果不想改动原数组的顺序,也可以用Set来确保选出来的题目不重复,直到凑够5个:
function getRandomQuestionsWithoutShuffle(questions, count) { const selectedIndices = new Set(); const result = []; // 直到选够count道不重复的题 while (selectedIndices.size < count) { // 生成0到题目总数-1的随机索引 const randomIndex = Math.floor(Math.random() * questions.length); // 如果这个索引没被选过,就加入结果 if (!selectedIndices.has(randomIndex)) { selectedIndices.add(randomIndex); result.push(questions[randomIndex]); } } return result; } // 调用示例 const quizQuestions2 = getRandomQuestionsWithoutShuffle(allQuestions, 5); console.log(quizQuestions2);
这个方法的特点:
- 完全保留原数组的顺序(只是选出来的题目是随机的)
- 逻辑简单易懂,新手也能快速上手
- 唯一小缺点:如果要选的数量接近数组总长度(比如99道),可能会多循环几次,但选5道的话完全没问题
小提示
- 只要页面刷新,
Math.random()就会生成新的随机数,所以每次打开测验都会拿到不同的题目 - 要是需要固定某一次的测验题目(比如让用户重测同一套),可以把随机种子存起来,但一般测验场景用不到这个
- 题目数组可以存在JSON文件里,或者从后端接口获取,前端拿到后直接用上面的方法处理就行
内容的提问来源于stack exchange,提问作者Antonio Andrés
相关产品推荐
相关产品推荐

