2

【对于问题的复杂性,我提前道歉……但有什么好问题是简单的?】

我为一个大型(22 名成员)制作支持团队管理待命名单。该列表是“全面升级”(列出所有团队成员)并每月生成。由于那些靠近列表顶部的人被称为隔夜问题(并且往往不可用),我们反向利用列表来创建我们的白天分配名册。

问题

经过不合理的时间,政治和争论(不要问)创建并同意生成这个名册的相当愚蠢的规则集。要生成每日分配名册:

“在待命名单上向后移动,选择名单上的“偶数”排名,然后按降序排列它们。然后对“赔率”做同样的事情,将它们放在名册上。”

所以,一个简单的例子:

随叫随到:“1-Jack,2-Jim,3-Jane,4-John,5-Jill,6-Joe”名册:“1-Joe,2-John,3-Jim,4-Jill,3-简,1-杰克”

主要的问题是,由于假期、PTO、其他任务等时间,待命列表很稀疏(可能有空位)。所以一个更真实的例子可能是:

待命:“1-Jack,3-Jane,4-John,6-Joe”名册:“1-Joe,2-John,3-Jane,4-Jack

真正的名单是22人。在任何给定的一天,我们平均大约有 17 或 18 个可用。失踪人员不会影响待命 - 你只是继续移动到下一个最高 - 但他们正在让名册规则内的工作变得痛苦。

当前(不优雅)的解决方案

目前我有这种工作蛮力风格。我首先创建了一个表示 on-call 的对象数组,其中每个对象都有一个人的姓名和 on-call 等级。(我确实突然想到,我可以通过创建一个仅包含索引代表实际排名的名称的稀疏数组来简化这一点......但我认为它不会改变问题)。

然后我从最后到第一个循环遍历数组两次:首先收集偶数排名(通过获取排名的模数)并将它们推送到新数组中,第二次收集赔率:

                       // 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 Web 服务中提取的当天信息。

同样,这工作正常,但需要在每天的处理中对相同的数据进行三个循环。

当前(损坏的)解决方案

我想要做的是到达我可以使用单个循环从待命生成名册的位置。直接进入,我一直致力于将后两个循环合并为一个。假设生成的 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; 

   }; 

这接近于工作,但往往会重叠(用第一个“奇数”覆盖最后一个“偶数”)或根据稀疏性和元素总数在偶数和赔率之间留下间隙。

结论

主要目标是直接在第一个循环中“即时”生成名册,而不是创建一个特定的 on-call 数组然后从中生成它 - 但目前我很乐意让第二个片段正常工作案例。

我也对这可能无法正常工作的可能性持开放态度。也许不优雅的规则集和不优雅的数据的组合只需要蛮力方法。如果是这样的话,我宁愿在放弃之前从比我自己更好的程序员那里听到它。

提前致谢。随时要求任何澄清。

4

2 回答 2

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);

您反过来遍历数组一次。对于每个人,根据他们的等级将它们附加到“偶数”或“赔率”。最后,您只需将两个数组连接成一个新的“名册”数组。

这是一个演示:

--- jsFiddle 演示 ---

很抱歉,这不是用您的特定变量名称编写的,但如果这是您正在寻找的,应该很容易改变它以适应您的环境。

于 2012-08-16T15:31:17.220 回答
0

这是咖啡脚本中非常相似的答案

# 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
于 2012-08-16T16:26:12.833 回答