[我为问题的复杂性提前道歉......但是什么好问题很简单?]
我管理一个大型(22名成员)生产支持团队的待命名单。该列表是“完全升级”(列出所有团队成员)并每月生成。由于靠近列表顶部的那些人被称为隔夜问题(并且往往不可用),我们反过来利用该列表来创建我们的日间分配名单。
在一段不合理的时间之后,政治和论证(不要问)制定了一个相当愚蠢的规则集,并同意产生这个名单。要生成每日作业名单:
“向后退出通话清单,在列表中选择”偶数“排名,然后按降序排列第一位。然后对”将赔率“放在名单上做同样的事情。”
所以,一个简单的例子:
随叫随到:“1-Jack,2-Jim,3-Jane,4-John,5-Jill,6-Joe” 名单:“1-Joe,2-John,3-Jim,4-Jill,3-Jane,1-Jack”
主要的皱纹是,由于休假,PTO,其他任务等时间,待命列表稀疏(可能有空位)。因此,一个更现实世界的例子可能是:
随叫随到:“1-Jack,3-Jane,4-John,6-Joe” 名单:“1-Joe,2-John,3-Jane,4-Jack
真正的名单是22人。在任何给定的一天,我们平均约17或18可用。失踪的人不会影响随叫随到 - 你只是继续前进到下一个最高点 - 但是他们正在让名册规则中的工作变得痛苦。
目前我有这种蛮力风格。我首先创建一个表示on-call的对象数组,其中每个对象都有一个人的名字和待命等级。 (我刚想到我可以通过创建一个稀疏数组来简化这一点,这些数组只是索引代表实际排名的名称......但我认为它不会改变这个问题。)
然后我从最后到第一个循环遍历数组:首先收集偶数等级(通过获得Rank的模数)并将它们推到一个新数组上,然后再收集几率:
// Get the Current Oncall
var Oncall = new Array();
for ( var iCnt = 1; iCnt <= 22; iCnt++ ) {
var CurOncall = DataRows[Cnt].getAttribute("ows_OnCall" + iCnt);
if ( CurOncall != null ) {
Oncall[Oncall.length] = {"Name":CurOncall, "Rank": iCnt};
};
};
// Get the Current Roster
var Roster = new Array();
// Add the "evens"
for ( var iCnt = Oncall.length - 1; iCnt >= 0; iCnt-- ) {
// Get the Current Incident Rank
if ( Oncall[iCnt].Rank % 2 == 0 ) {
Roster[Roster.length] = Oncall[iCnt].Name;
};
}
// Add the "odds"
for ( var iCnt = Oncall.length - 1; iCnt >= 0; iCnt-- ) {
// Get the Current Incident Rank
if ( Oncall[iCnt].Rank % 2 != 0 ) {
Roster[Roster.length] = Oncall[iCnt].Name;
};
}
请注意,此代码段存在于更大的循环中(我循环了一周的数据,这只是一天)。 DataRows [Cnt] 是从SharePoint网络服务中提取的当天信息。
同样,这种方法很好,但是对于每天的处理,需要在同一数据上进行三次循环。
我想做的就是进入poing,我可以使用单个循环从通话中生成名册。直接进入,我一直在努力将后两个循环合二为一。假设Oncall数组生成与上面相同,这是我目前的尝试(它有点难看):
var IncCnt = 1;
for ( var Cnt = OnCall.length - 1; Cnt >= 0; Cnt-- ) {
// Get the Current Incident (Roster) Rank
if ( OnCall[Cnt].Rank % 2 == 0 ) {
CurIncRank = Math.ceil(IncCnt / 2);
} else {
CurIncRank = Math.ceil(IncCnt / 2) + Math.floor(OnCall.length / 2)
};
Roster[CurIncRank] = OnCall[Cnt].Name;
// Increase the Incident Cnt
IncCnt = IncCnt + 1;
};
这接近于工作,但往往要么重叠(用最后的“偶数”覆盖第一个“奇数”),要么根据稀疏度和元素总数在均匀和赔率之间留一个间隙。
主要目标是直接在第一个循环中“动态”生成名单,而不是创建一个特定的随叫随到阵列然后从中生成 - 但目前我很乐意接受第二个snippt到在所有情况下工作。
我也很乐意这可能无法工作。也许,不优雅的规则集和不优雅的数据的组合只需要蛮力方法。如果是这种情况,我宁愿在放弃之前从比我更好的程序员那里听到它。
提前致谢。随意请求任何澄清。
答案 0 :(得分:2)
所以,如果我正确地读了你,你有一个'onCall'对象数组,每个对象都包含一个名字和等级,如下所示:
var onCall = [
{
rank: 1,
name: 'Jack'
},
{
rank: 3,
name: 'Jill'
},
...
];
然后,您要创建一个名单数组,其中按降序排列均匀排名的人,然后按降序排列奇数排名的人。如果这是正确的,那么以下代码将生成这样的数组:
for(var i = onCall.length-1; i >= 0; i--) {
person = onCall[i];
if(person.rank % 2 === 0) {
evens.push(person);
} else {
odds.push(person);
}
}
roster = evens.concat(odds);
你反过来一次完成数组。对于每个人,根据他们的等级将他们添加到'平均'或'赔率'。最后,您只需将两个数组连接成一个新的“名册”数组。
这是一个演示:
我很抱歉这不是用你的特定变量名写的,但是如果这是你正在寻找的,那么它应该很容易改变以适应你的环境。
答案 1 :(得分:0)
这是coffeescript中非常相似的答案(:
# List of all employees
employees = [
{ name: "Jack", onCall: false, Rank: 1 }
{ name: "Jim", onCall: true, Rank: 2 }
{ name: "Jane", onCall: false, Rank: 3 }
{ name: "John", onCall: false, Rank: 4 }
{ name: "Jill", onCall: true, Rank: 5 }
{ name: "Joe", onCall: false, Rank: 6 }
]
# Returns an array of eligible Employees in the order which they should be called
generateRoster = (employees) ->
a = []
b = []
employees
.reverse()
.filter (employee) ->
not employee.onCall
.forEach (employee) ->
if employee % 2
a.push(employee)
else
b.push(employee)
return
a.concat(b)
# Output the roster
console.log generateRoster employees