lrf402788946 4 years ago
parent
commit
65de95650e
1 changed files with 106 additions and 93 deletions
  1. 106 93
      app/service/class.js

+ 106 - 93
app/service/class.js

@@ -42,7 +42,6 @@ class ClassService extends CrudService {
     const claGroup = _.groupBy(newclass, 'batchid');
     const keys = Object.keys(claGroup);
     const result = {}; // key:班级id;value:学生id数组
-    const pList = []; // 补人结果
     // 循环批次
     for (const bkey of keys) {
       const classList = claGroup[bkey]; // 该批次下的班级列表
@@ -75,9 +74,10 @@ class ClassService extends CrudService {
 
       }
       // 验证最佳结果是否超出班级的最少人数,不是,则处理
+      // console.log('计算最优解');
       solve = this.checkSolve(solve, minNumber, classnum);
-      console.log(solve);
       // 塞人
+      // console.log('塞人前');
       for (const c of classList) {
         const { _id } = c;
         if (!(result[_id] && _.isArray(result[_id]))) result[_id] = [];
@@ -95,55 +95,125 @@ class ClassService extends CrudService {
           studentGroup[key] = sList;
         }
       }
-      // 补人
-      for (const c of classList) {
-        const { _id, number, name } = c;
-        let nowNum = result[_id].length;
-        const soldup = _.cloneDeep(solve);
-        while (nowNum < number) {
-        // 补人,根据solve,获取补人的选择列表
-          const res = this.getSelects(soldup);
-          for (const r of res) {
-            const { schid, gender } = r;
-            // 获取学生列表
-            const sList = studentGroup[`${schid}-${gender}`];
-            const head = _.head(sList);
-            if (head) {
-              // 有学生,往班级里推,备选中删除,重新计算当前分配的班级人数,修改solve副本
-              // result[_id].push(head._id);
+      // console.log('塞人后');
+      // console.log('补人前');
+      // 检查是否有学生剩余,如果有学生剩余,都需要继续进行人的处理,无论是补人还是加人.
+      let els = _.flatten(Object.values(studentGroup)).length;
+      // 没有剩余的学生,下面也没法处理,结束了(跳过while了)
+      while (els > 0) {
+        // 还有学生,那就需要继续处理,看看是补人还是加人
+        // 检查各个班级是否达到人数要求
+        const { ok, not } = this.checkClassStatus(result, classList);
+        // 如果not里有值,说明还有班级没满足人数要求->补人
+        // 如果not没有值,说明参培人员多了->分到每个班里
+        if (not.length > 0) {
+        // 进行补人
+          // not中的每个班进行补人,每个班补一个人(result[classid]加人),studentGroup[key]减人
+          // 如果没人了,break;
+          for (const c of not) {
+            // 需要计算出这个班补人的最优解
+            const { _id } = c;
+            const stuList = result[_id];
+            const claSolve = this.getClassSolve(stuList);
+            // 根据solve结果,取对应的值,然后做加减
+            for (const s of claSolve) {
+              const { schid, gender } = s;
+              let midList = studentGroup[`${schid}-${gender}`];
+              if (midList.length <= 0) continue;
+              const head = _.head(midList);
+              result[_id].push(head);
+              midList = _.drop(midList);
+              studentGroup[`${schid}-${gender}`] = midList;
+              break;// 一次,一班只补一个的重要关键词
+            }
+          }
+        } else {
+        // 额外加人
+        // 说明下这里为什么要ok:因为在上面的solve,强制以班级最少的人数为均分标准
+        // 所以在班级人数不均等的情况下,出现某班均分完是正好的人数,剩下的班少人,但这时还得先把少人的班先补上才能均摊多的人
+        // 为什么要说明,因为下面代码除了循环的 数组 外,都一样啊
+          for (const c of ok) {
+          // 需要计算出这个班补人的最优解
+            const { _id } = c;
+            const stuList = result[_id];
+            const claSolve = this.getClassSolve(stuList);
+            // 根据solve结果,取对应的值,然后做加减
+            for (const s of claSolve) {
+              const { schid, gender } = s;
+              let midList = studentGroup[`${schid}-${gender}`];
+              if (midList.length <= 0) continue;
+              const head = _.head(midList);
               result[_id].push(head);
-              studentGroup[`${schid}-${gender}`] = _.drop(sList);
-              nowNum = result[_id].length;
-              soldup[`${schid}-${gender}`].res++;
-              pList.push(`${name}班用${schid}-${gender}补人:当前人数为${nowNum};要求${number}`);
+              midList = _.drop(midList);
+              studentGroup[`${schid}-${gender}`] = midList;
               break;
-            } else continue;
+            }
           }
         }
-
+        // 重新计算人数,就是上面的els计算再执行一次
+        els = _.flatten(Object.values(studentGroup)).length;
       }
+
+
     }
-    // console.log(pList);
     // for (const key in result) {
     //   console.group(key);
     //   const list = result[key];
     //   const b = list.filter(f => f.gender === '男');
     //   const g = list.filter(f => f.gender === '女');
-    //   console.log(b.length, g.length);
+    //   console.log(list.length, b.length, g.length);
     //   console.groupEnd();
     // }
 
     // 更新学生的班级
-    const ckeys = Object.keys(result);
-    for (const classid of ckeys) {
-      await this.stumodel.updateMany({ _id: result[classid] }, { classid });
-    }
-    // 新添,给学生排序号
-    const claList = await this.model.find({ termid });
-    for (const cla of claList) {
-      await this.ctx.service.student.arrangeNumber({ classid: cla._id });
-    }
+    // const ckeys = Object.keys(result);
+    // for (const classid of ckeys) {
+    //   await this.stumodel.updateMany({ _id: result[classid] }, { classid });
+    // }
+    // // 新添,给学生排序号
+    // const claList = await this.model.find({ termid });
+    // for (const cla of claList) {
+    //   await this.ctx.service.student.arrangeNumber({ classid: cla._id });
+    // }
   }
+
+  /**
+   * 获取某班补人的最优解列表
+   * @param {Array} list 某班级的学生列表
+   */
+  getClassSolve(list) {
+    // 因为按总人数的最优解已经均分过了,所以此处只计算,如何让该班平衡的最优解,不考虑整体了
+    const schGroup = _.groupBy(list, 'schid');
+    const midArr = [];
+    for (const key in schGroup) {
+      const midList = schGroup[key];
+      const bl = midList.filter(f => f.gender === '男');
+      midArr.push({ schid: key, gender: 'boy', number: bl.length });
+      const gl = midList.filter(f => f.gender === '女');
+      midArr.push({ schid: key, gender: 'girl', number: gl.length });
+    }
+    // 按 人数升序, 性别先男后女
+    return _.orderBy(midArr, [ 'number', 'gender' ], [ 'asc', 'desc' ]);
+  }
+
+  /**
+   * 检查班级是否达到人数
+   * @param {Array} alreadyList 已分配的列表
+   * @param {Array} classList 班级列表
+   */
+  checkClassStatus(alreadyList, classList) {
+    let ok = []; // 已经满足人数的班级
+    const not = []; // 未满足人数的班级
+    for (const c of classList) {
+      const { _id, number } = c;
+      const nowNum = alreadyList[_id].length;
+      if (nowNum < number) not.push(c); else ok.push(c);
+    }
+    // 需要排序,需要按上限人数排列,把人少的放上面
+    ok = _.orderBy(ok, [ 'number' ], [ 'asc' ]);
+    return { ok, not };
+  }
+
   /**
    * 算整除和取余
    * @param {Any} num1 性别人数
@@ -187,64 +257,7 @@ class ClassService extends CrudService {
     }
     return solve;
   }
-  // 获取选择结果
-  getSelects(solve) {
-    // 做出补人选项的集合:按学校人数,性别人数来看
-    const keys = Object.keys(solve);
-    let schids = keys.map(i => {
-      const arr = i.split('-');
-      let res;
-      if (arr[0] && parseInt(arr[0])) res = arr[0];
-      return res;
-    });
-    schids = _.compact(_.uniq(schids));
-    let genders = keys.map(i => {
-      const arr = i.split('-');
-      return arr[1];
-    });
-    genders = _.compact(_.uniq(genders));
-    let schArr = [];
-    for (const schid of schids) {
-      const midKeys = keys.filter(f => f.includes(schid));
-      let count = 0;
-      for (const k of midKeys) {
-        count += solve[k].res;
-      }
-      const obj = { schid, count };
-      schArr.push(obj);
-    }
-    let genArr = [];
-    for (const gen of genders) {
-      const midKeys = keys.filter(f => f.includes(gen));
-      let count = 0;
-      for (const k of midKeys) {
-        count += solve[k].res;
-      }
-      const obj = { gender: gen, count };
-      genArr.push(obj);
-    }
-    // 2个数组升序排序
-    schArr = _.orderBy(schArr, [ 'count' ], [ 'asc' ]);
-    genArr = _.orderBy(genArr, [ 'count' ], [ 'asc' ]);
-    const arr = [];
-    // 优先性别
-    // for (const gen of genArr) {
-    //   for (const sch of schArr) {
-    //     const { schid } = sch;
-    //     const { gender } = gen;
-    //     arr.push({ schid, gender });
-    //   }
-    // }
-    // 优先学校
-    for (const sch of schArr) {
-      for (const gen of genArr) {
-        const { schid } = sch;
-        const { gender } = gen;
-        arr.push({ schid, gender });
-      }
-    }
-    return arr;
-  }
+
 
   // 取得同样类型的学生
   async getstutype(_students, type) {