【发布时间】:2020-05-23 06:26:12
【问题描述】:
我有 149 个小组,由大约 250 个名单中的个人组成。分组(部落)组成是固定的,也就是说每组的3名成员不能互换。我需要创建一个时间表(总共 6 天),将 149 组每天分成 25 组,除了最后一天,条件是每个人每天的出现次数不得超过 1 次。
Here is a copy 我的数据集的虚拟名称。
到目前为止,这是我的 Google Apps 脚本代码:
var ui = SpreadsheetApp.getUi();
var sht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Tribes');
var schedSht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Schedule');
var nameSht = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Names');
var tribesArr = sht.getRange(2, 1, sht.getLastRow() - 1, 1).getValues();
var tribesOrder = tribesArr.map(function(t) { return t[0] });
tribesArr = tribesArr.map(function(t) { return t[0] });
var tribes = randomize(tribesArr);
var takenTribes = [];
var tribeSet = [];
var nameSet = [];
var LastDayTribeNum = 24;
var otherDaysTribeNum = 25;
var numDays = 6;
function makeMenu() {
ui.createMenu('My Menu').addItem('Create Randomized Schedule', 'makeSchedule').addToUi();
}
function makeSchedule() {
var dayNum = 1;
while (dayNum < numDays + 1) {
var remainingTribes = tribes.filter(function(r) { return takenTribes.indexOf(r) < 0; });
var daySched = fillUpDay(dayNum, remainingTribes);
tribeSet.push(daySched.tribes);
nameSet.push(daySched.names);
dayNum++;
}
remainingTribes = tribes.filter(function(r) { return takenTribes.indexOf(r) < 0; });
if (takenTribes.length < tribes.length) {
remainingTribes.forEach(swap);
}
tribeSet.forEach(function(tribe) {
schedSht.appendRow(tribe);
});
nameSet.forEach(function(name) {
nameSht.appendRow(name);
});
}
function fillUpDay(revDay, remTribes) {
var sched = {};
var namesToday = [];
var tribesToday = [];
var currIdx = 0;
var tribeMaxNum = (revDay === numDays) ? LastDayTribeNum : otherDaysTribeNum;
while (tribesToday.length < tribeMaxNum && currIdx < remTribes.length) {
var row = tribesOrder.indexOf(remTribes[currIdx]) + 2;
var currNames = sht.getRange(row, 2, 1, 3).getValues()[0];
var nameFound = false;
//check if name of tribe already in today's list
for (var t = 0; t < 3; t++) {
if (namesToday.indexOf(currNames[t]) !== -1) {
nameFound = true;
}
}
if (!nameFound) {
//if names of all three not in the list, add all three to today's list and remove tribe from list of unscheduled tribes
namesToday = namesToday.concat(currNames);
tribesToday.push(remTribes[currIdx]);
takenTribes.push(remTribes[currIdx]);
currIdx++;
} else {
//go to next tribe
currIdx++;
}
}
sched.tribes = tribesToday;
sched.names = namesToday;
return sched;
}
function swap(tribeToSwap) {
var row = tribesOrder.indexOf(tribeToSwap) + 2;
var namesInTribe = sht.getRange(row, 2, 1, 3).getValues()[0];
var len = nameSet.length;
var idx = 0;
var found = checkInSet(namesInTribe, nameSet[idx]);
var swapped = false;
while (!swapped && idx < len - 1) {
if (!found) {
// try swap
var tempNameArr = nameSet[idx];
tempNameArr.slice(3);
tempNameArr.push(namesInTribe);
var removedNames = nameSet[idx];
removedNames.slice(0, 3);
var lastNames = nameSet[len - 1];
var good = true;
for (var c = 0; c < 3; c++) {
if (lastNames.indexOf(removedNames[c]) > -1) {
good = false;
}
}
if (good) {
// swap
tribeSet[idx].slice(1);
nameSet[idx] = tempNameArr;
tribeSet[len - 1].push(tribeToSwap);
nameSet[len - 1].push(removedNames);
swapped = true;
}
} else {
// try next day
idx++;
found = checkInSet(namesInTribe, nameSet[idx]);
}
}
}
function checkInSet(names, setNames) {
var found = false;
for (var idx = 0; idx < names.length; idx++) {
if (setNames.indexOf(names[idx]) > -1) {
found = true;
}
}
return found;
}
function randomize(array) {
//https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
var currentIndex = array.length,
temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
我所做的是每天创建一个数组并检查当前索引的相应组(部落)的成员是否存在于当天的名称数组中,如果找到则转到下一个索引直到当天的配额( 25) 到达。如果当天没有找到姓名,该部落将被标记为已被占用,并且将不再包含在随后的时间表中。结果将附加到各自的工作表中。如果因为那天已经出现了一个名字而导致部落不匹配,我会尝试在另一天交换它。
代码大部分时间都在运行(大约 5 秒内完成)。其他时候,它会运行几分钟,我会取消它。但是,我从来没有在任何跑步中得到我需要的东西。我将在日程表中得到 149 个部落,但是当我检查名称时,我没有得到 447 个名称(每天没有重复)。我无法确定在哪里调整算法。我希望有人至少可以给出提示,更好的解决方案。请原谅乱码。
【问题讨论】:
标签: javascript arrays google-apps-script random google-sheets