You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS从含嵌套数组的数组选取x个随机元素 每个嵌套数组最多选1个

健身随机训练动作选取工具 互斥逻辑实现

核心需求

  • 支持用户自定义选取n个健身训练动作
  • 同组互斥动作(例如不同姿势引体向上、不同距离划船)单次生成结果中最多出现1个
  • 动作库统一采用嵌套数组格式,无互斥关系的单独动作存为长度为1的子数组,方便后续维护扩展

原有逻辑缺陷

原有实现直接对扁平化的动作列表整体洗牌后截取前n项,无法识别互斥分组,会出现同组多个动作同时被选中的问题。

实现方案

  1. 重构动作库结构:将所有互斥动作归入同一子数组,独立动作单独存为单元素子数组
  2. 调整随机规则:先对外层的动作组做随机排序,遍历乱序后的动作组时,每组随机抽取1个动作加入结果集
  3. 边界处理:将选择滑块的最大值设置为动作组总数量,避免用户选择超过可选上限的数值(每组最多出1个动作,可选最大数量等于动作组总数)
  4. 结果集长度达到用户指定的n时立即停止遍历,减少不必要的计算

可直接运行的完整代码

// 获取滑块选中的动作数量
function getNumber(){
    return Number(document.getElementById("userInput").value)
}

// 通用数组洗牌函数
function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
    return array
}

// 主生成按钮触发函数
function myFunction() {
    const selectCount = getNumber() 
    // 清空上一轮生成的动作列表
    document.getElementById("todays_exercises").innerHTML = "";

    // 重构后的动作库:同一子数组内为互斥动作
    const exerciseGroups = [ 
        [" air squats ×40"],
        [" skip ×200"],
        [" burpees ×20"],
        [" row 500m", " row 250m"],
        [" pull-ups ×10", " finger board pull-ups ×10", " ring pull-ups ×10"],
        [" sit-ups ×40"],
        [" press-ups ×25"],
        [" lunges ×20"],
        [" curls ×15"],
        [" ring rows ×12"],
        [" assisted ring dips ×10"],
        [" ring push ups ×10"],
        [" power snatch ×10"],
        [" power clean ×20"],
        [" power clean & jerk ×15"],
        [" hanging leg raises ×20"],
        [" bench press ×10"],
        [" calf raises ×20"],
        [" plank 20s"],
        [" dips ×20"]
    ];

    // 设置滑块可选最大值
    document.getElementById("userInput").setAttribute('max', exerciseGroups.length);

    // 打乱动作组顺序
    const shuffledGroups = shuffleArray([...exerciseGroups])
    const selected = []

    // 逐组随机抽取动作,选够数量即停止
    for (const group of shuffledGroups) {
        if (selected.length >= selectCount) break
        const randomIdx = Math.floor(Math.random() * group.length)
        selected.push(group[randomIdx])
    }

    // 渲染结果到页面
    selected.forEach(item => {
        document.getElementById("todays_exercises").innerHTML += `<li>${item}</li>`
    });
}

维护说明

后续新增动作时,如果是独立无互斥的动作,直接在exerciseGroups数组中新增一个单元素子数组即可;如果是和现有动作互斥的新动作,直接加到对应互斥组的子数组中,不需要修改选取逻辑。


内容的提问来源于stack exchange,提问作者Mark Evans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 04:48:18