2

[問題が複雑であることを前もってお詫びします...しかし、単純な良い問題とは何ですか?]

大規模な (22 メンバー) 制作サポート チームのオンコール名簿を管理しています。リストは「完全なエスカレーション」 (すべてのチーム メンバーがリストされます) であり、毎月生成されます。リストの一番上に近い人は夜間の問題に呼び出されるため (そして、利用できない傾向があるため)、逆にリストを活用して日中の割り当て名簿を作成します。

問題

理不尽な時間、政治、議論 (聞かないでください) を経て、かなりばかげたルールセットが作成され、この名簿を生成することに同意しました。毎日の割り当て名簿を生成するには:

「オンコールリストをさかのぼって、リストの「偶数」ランクを選択し、降順で最初に配置します。次に、「オッズ」についても同じことを行い、それらを名簿に配置します。」

したがって、簡単な例:

オンコール: "1-ジャック、2-ジム、3-ジェーン、4-ジョン、5-ジル、6-ジョー" 名簿: "1-ジョー、2-ジョン、3-ジム、4-ジル、3-ジェーン、ワンジャック」

主な問題は、休暇、有給休暇、その他の割り当てなどのために、オンコール リストがまばらになることです (空のスロットがある可能性があります)。したがって、より現実的な例は次のようになります。

オンコール: "1 ジャック、3 ジェーン、4 ジョン、6 ジョー" 名簿: "1 ジョー、2 ジョン、3 ジェーン、4 ジャック

実際のリストは 22 人です。ある特定の日には、平均して約 17 人か 18 人が利用可能です。行方不明者がオンコールに影響を与えることはありません - 次の最高位に移動し続けるだけです - しかし、彼らは名簿規則内で働くことを苦痛にしています.

現在の(洗練されていない)ソリューション

現在、私はこのブルートフォーススタイルを使用しています。最初に、オンコールを表すオブジェクトの配列を作成します。各オブジェクトには、人の名前とオンコール ランクが含まれます。(インデックスが実際のランクを表す名前だけのスパース配列を作成することで、おそらくこれを単純化できると思いました...しかし、それで問題が変わるとは思いません)。

次に、配列を最後から最初に 2 回ループします。最初に (ランクのモジュラスを取得することによって) 偶数のランクを収集し、それらを新しい配列にプッシュし、2 番目にオッズを収集します。

                       // 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; 
                   }; 
           } 

このスニペットは、より大きなループ内に存在することに注意してください (1 週間分のデータをループしていますが、これは 1 日だけです)。 DataRows[Cnt]は、SharePoint Web サービスから取得した当日の情報です。

繰り返しますが、これは正常に機能しますが、毎日の処理で同じデータを 3 回ループする必要があります。

現在の(壊れた)ソリューション

私がやりたいことは、単一のループを使用してオンコールから名簿を生成できる場所に到達することです。そこに直接移行して、2 番目の 2 つのループを 1 つに結合することに取り組んできました。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; 

   }; 

これはほぼ機能しますが、重複する (最後の「偶数」を最初の「奇数」で上書きする) か、要素のまばらさと合計数に応じて偶数と奇数の間にギャップを残す傾向があります。

結論

主な目標は、特定のオンコール配列を作成してからそれを生成するのではなく、最初のループで「その場で」名簿を直接生成することですが、現在、2番目のスニペットだけをすべて機能させることに満足しています。ケース。

また、これがうまくいかない可能性もあります。おそらく、洗練されていないルールセットと洗練されていないデータの組み合わせには、単純に力ずくの方法が必要です。その場合は、あきらめる前に、自分よりも優れたプログラマーから聞いてみたいと思います。

前もって感謝します。ご不明な点がございましたら、お気軽にお問い合わせください。

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

逆に、配列を 1 回通過します。各人について、ランクに応じて「evens」または「odds」のいずれかに追加します。最後に、2 つの配列を新しい「名簿」配列に連結するだけです。

ここにデモがあります:

--- jsFiddle デモ ---

これが特定の変数名で書かれていないことをお詫びしますが、これが探しているものであれば、環境に合わせて簡単に変更できるはずです。

于 2012-08-16T15:31:17.220 に答える
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
于 2012-08-16T16:26:12.833 に答える