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

如何在同一JSON对象数组中比较元素并生成无冲突课程表

课程冲突检测与无冲突日程生成方案

一、数据预处理(修复格式+转换为可计算结构)

首先修正你提供的JSON格式错误(键名需加引号,值格式规范),再将原始数据转换为便于冲突判断的结构:

// 修正后的原始课程数据
const rawCourses = [
  {
    "course code": "act 227",
    "course name": "science",
    "section": "12345",
    "status": "closed",
    "day": "1 3 5",
    "time": "8 AM-9AM",
    "final date": "3/4/2023"
  },
  {
    "course code": "mat 147",
    "course name": "science",
    "section": "12346",
    "status": "open",
    "day": "2 4",
    "time": "11AM-12PM",
    "final date": "3/6/2023"
  },
  // 更多课程数据...
];

// 数据预处理函数
function preprocessCourses(rawData) {
  return rawData.map(course => {
    // 上课日转数字数组(1=周一,2=周二...)
    const days = course["day"].split(" ").map(Number);
    // 时间转当日分钟数(便于重叠判断)
    const [startStr, endStr] = course["time"].split("-");
    const startMinutes = convertTimeToMinutes(startStr.trim());
    const endMinutes = convertTimeToMinutes(endStr.trim());
    // 期末日期转Date对象
    const finalDate = new Date(course["final date"]);

    return {
      ...course,
      days,
      startMinutes,
      endMinutes,
      finalDate,
      isAvailable: course["status"].toLowerCase() === "open"
    };
  });
}

// 辅助函数:将12小时制时间转成当日分钟数(如"8 AM" → 480)
function convertTimeToMinutes(timeStr) {
  const [time, period] = timeStr.split(" ");
  let [hours, minutes] = time.split(":").map(Number);
  minutes = minutes || 0;

  if (period === "PM" && hours !== 12) hours += 12;
  if (period === "AM" && hours === 12) hours = 0;

  return hours * 60 + minutes;
}

// 预处理后的数据(后续逻辑基于此)
const processedCourses = preprocessCourses(rawCourses);

二、冲突判断核心逻辑

编写函数判断两个课程小节是否存在冲突,冲突包含两个维度:期末日期相同、同一上课日且时间段重叠:

// 判断两个小节是否冲突
function isConflict(sectionA, sectionB) {
  // 1. 期末日期相同则冲突
  if (sectionA.finalDate.getTime() === sectionB.finalDate.getTime()) {
    return true;
  }

  // 2. 存在共同上课日且时间段重叠则冲突
  const hasCommonDay = sectionA.days.some(day => sectionB.days.includes(day));
  if (!hasCommonDay) return false;

  // 时间段重叠判断:A的开始 < B的结束 且 A的结束 > B的开始
  const isTimeOverlap = sectionA.startMinutes < sectionB.endMinutes 
                      && sectionA.endMinutes > sectionB.startMinutes;
  return isTimeOverlap;
}

// 判断一个小节组合是否完全无冲突
function isCombinationValid(combination) {
  for (let i = 0; i < combination.length; i++) {
    for (let j = i + 1; j < combination.length; j++) {
      if (isConflict(combination[i], combination[j])) return false;
    }
  }
  return true;
}

三、生成无冲突课程组合

根据用户输入的课程代码,获取对应开放小节,生成所有可能的组合并过滤出无冲突的:

// 获取指定课程的所有开放小节
function getCourseSections(courseCode) {
  return processedCourses.filter(course => 
    course["course code"] === courseCode && course.isAvailable
  );
}

// 生成多个数组的笛卡尔积(所有小节组合)
function cartesianProduct(arrays) {
  return arrays.reduce((acc, curr) => {
    return acc.flatMap(item => curr.map(subItem => [...item, subItem]));
  }, [[]]);
}

// 根据用户输入的课程代码,生成无冲突组合
function generateValidCombinations(targetCourseCodes) {
  // 获取每个课程的开放小节列表
  const sectionLists = targetCourseCodes.map(code => getCourseSections(code));
  
  // 过滤无开放小节的课程
  const validSectionLists = sectionLists.filter(list => list.length > 0);
  if (validSectionLists.length !== targetCourseCodes.length) {
    alert("部分课程没有开放小节");
    return [];
  }

  // 生成所有可能的组合,再过滤无冲突的
  const allCombinations = cartesianProduct(validSectionLists);
  return allCombinations.filter(combination => isCombinationValid(combination));
}

四、前端交互实现示例

假设用户输入课程代码(逗号分隔),点击按钮后动态渲染无冲突日程:

<!-- HTML结构 -->
<div>
  <input type="text" id="courseCodesInput" placeholder="输入课程代码,逗号分隔(如act 227, mat 147)">
  <button onclick="handleGenerate()">生成无冲突日程</button>
  <div id="scheduleResults"></div>
</div>
// 前端交互函数
function handleGenerate() {
  const input = document.getElementById("courseCodesInput").value.trim();
  if (!input) {
    alert("请输入课程代码");
    return;
  }

  const targetCourseCodes = input.split(",").map(code => code.trim());
  const validCombinations = generateValidCombinations(targetCourseCodes);
  const resultsContainer = document.getElementById("scheduleResults");
  resultsContainer.innerHTML = "";

  if (validCombinations.length === 0) {
    resultsContainer.innerHTML = "<p>未找到无冲突的课程组合</p>";
    return;
  }

  // 渲染每个无冲突日程选项
  validCombinations.forEach((combination, index) => {
    const scheduleDiv = document.createElement("div");
    scheduleDiv.className = "schedule-option";
    scheduleDiv.innerHTML = `
      <h3>可选日程 ${index + 1}</h3>
      <table border="1" cellpadding="8">
        <tr>
          <th>课程代码</th><th>课程名称</th><th>小节</th><th>上课日</th><th>时间</th><th>期末日期</th>
        </tr>
        ${combination.map(section => `
          <tr>
            <td>${section["course code"]}</td>
            <td>${section["course name"]}</td>
            <td>${section["section"]}</td>
            <td>${section.days.join("、")}</td>
            <td>${section["time"]}</td>
            <td>${section.finalDate.toLocaleDateString()}</td>
          </tr>
        `).join("")}
      </table>
    `;
    resultsContainer.appendChild(scheduleDiv);
  });
}

关键说明

  • 仅处理**开放状态(open)**的小节,自动过滤closed的;
  • 若课程数量较多(如超过4门),可将笛卡尔积替换为回溯法减少计算量;
  • 时间转换、冲突规则可根据实际需求调整(比如支持24小时制、忽略期末日期冲突等)。

内容的提问来源于stack exchange,提问作者mimimo the great

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 21:24:57