3

私は自分が抱えている問題を解決するアルゴリズムに取り組んでいますが、少し行き詰まっています。シナリオは次のとおりです。

orderという変数を含むオブジェクトがあります。

public class Item
{
     public int Order{get; set;};

     public int ID{get; set;}; // not incremented can be any value!
}

だから私はこれらのリストを持っています:

List<Item> list = new List<Item>().OrderBy((o) => o.Order);

そして、いつでも注文値を変更することができます。したがって、最初のアイテムの注文値を変更したい場合は、他のすべての注文値をそれに応じて更新して、重複がないようにする必要があります。

for (int i = 0; i <= list .Count - 1; i++)
{
    if (list [i].ID == inputID)
    {
        list [i].Order = inputNewPosition;
    }
    else
    {
        if (list [i].Order < inputNewPosition)
        {
            list [i].Order --;
        }
        else
        {
             list [i].Order ++;
        }
    }
}

最後のアイテムの順序を最初に変更すると、最初のアイテムの順序が0になるため、これは失敗します。

誰か助けてもらえますか?

ありがとう

4

3 に答える 3

5

リスト内の要素の4つの状況を見てみましょう(それらを繰り返し処理します)。(簡潔にするために)私たちoldが移動しているアイテムを古い位置とnewし、新しい位置にする場合、リスト内のアイテムについて次の場合があります(これを明確にするために紙に引き出してください)。

  1. 現在のアイテムは移動するアイテムです:直接移動します
  2. 現在のアイテムの順序は<newおよび<oldです:移動しないでください
  3. 現在のアイテムの順序は≥newおよび< old:右に移動します
  4. 現在のアイテムの順序は≤newかつ> old:左に移動します
  5. 現在のアイテムの順序は>newおよび> old:移動しないでください

列挙を開始すると、移動するアイテムがどこに移動するか(でnew)はわかりますが、どこから来たのかはわかりません(old)。ただし、リストの最初から列挙を開始すると、各ステップで、実際に表示されるまでリストのさらに下にある必要があることがわかります。したがって、フラグ()を使用して、seenまだ見たかどうかを示すことができます。つまりseen、falseは<を意味oldし、trueは>=を意味しますold

bool seen = false;
for (int i = 0; i < items.Length; i++)
{
    if (items[i].ID == inputID)
    {
        items[i].Order = inputNewPosition;
        seen = true;
    }
}

このフラグは、現在のアイテムが>= oldであるかどうかを示します。これで、この知識と上記のルールに基づいて、入換を開始できます。(したがってnew、上記の説明では、変数で表すinputNewPosition前か後かを示します。)oldseen

bool seen;
for (int i = 0; i < items.Count; i++)
{
    if (items[i].ID == inputID) // case 1
    {
        items[i].Order = inputNewPosition;
        seen = true;
    }
    else if (seen) // cases 4 & 5
    {
        if (items[i].Order <= inputNewPosition) // case 4
        {
           items[i].Order--; // move it left
        }
    }
    else // case 2 & 3
    {
        if (items[i].Order >= inputNewPosition) // case 3
        {
            items[i].Order++; // move it right
        }            
    }
}

以上のことをすべて言っても、変更ごとにコレクションを並べ替える方がおそらく簡単です。デフォルトの並べ替えアルゴリズムは、ほぼ並べ替えられたコレクションでかなりすっきりしているはずです。

于 2013-02-14T17:45:18.890 に答える
0

あなたの質問はあまり明確ではありませんが、要件については、Orderを含むオブジェクトでイベントを実行し、それを監視できるコンテナオブジェクトを用意するのが最善の方法です。ただし、その場合は、順番に表示するという問題に対処するのが非常に厄介な方法のように思われるため、アルゴリズムを再考することをお勧めします。

そうは言っても、問題の要件は何ですか?アイテム#2から#5の順序を切り替えると、#3はどうなりますか?それは現在の場所に残りますか、それとも#6にする必要がありますか?

于 2013-02-14T18:13:15.740 に答える
0

これが私が問題を解決した方法ですが、もっと賢い方法があるかもしれないと思います。

更新する必要があるオブジェクトは、ポリシーワークロードアイテムです。これらのそれぞれに優先順位が関連付けられています。同じ優先度のポリシーワークロードアイテムは存在できません。したがって、ユーザーが優先度を更新すると、それに応じて他の優先度を上下にシフトする必要があります。

このハンドラーはリクエストオブジェクトを受け取ります。リクエストにはIDと優先度があります。

 public class UpdatePriorityCommand
 {
     public int PolicyWorkloadItemId { get; set; }
     public int Priority { get; set; }
 }

このクラスは、次のコードでリクエストオブジェクトを表します。

//Get the item to change priority
PolicyWorkloadItem policyItem = await _ctx.PolicyWorkloadItems
                                          .FindAsync(request.PolicyWorkloadItemId);

//Get that item's priority and assign it to oldPriority variable
int oldPriority = policyItem.Priority.Value;

//Get the direction of change. 
//-1 == moving the item up in list
//+1 == moving the item down in list
int direction = oldPriority < request.Priority ? -1 : 1;

//Get list of items to update... 
List<PolicyWorkloadItem> policyItems = await _ctx.PolicyWorkloadItems
                                                 .Where(x => x.PolicyWorkloadItemId != request.PolicyWorkloadItemId)
                                                 .ToListAsync();

//Loop through and update values
foreach(var p in policyItems)
{
    //if moving item down in list (I.E. 3 to 1) then only update
    //items that are less than the old priority. (I.E. 1 to 2 and 2 to 3)
    //items greater than the new priority need not change (i.E. 4,5,6... etc.)

    //if moving item up in list (I.E. 1 to 3)
    //items less than or equal to the new value get moved down. (I.E. 2 to 1 and 3 to 2)
    //items greater than the new priority need not change (i.E. 4,5,6... etc.)
    if(
           (direction > 0 && p.Priority < oldPriority)
        || (direction < 0 && p.Priority > oldPriority && p.Priority <= request.Priority)
      )
    {  
        p.Priority += direction;
        _ctx.PolicyWorkloadItems.Update(p);
    }       
}

//finally update the priority of the target item directly
policyItem.Priority = request.Priority;

//track changes with EF Core
_ctx.PolicyWorkloadItems.Update(policyItem);

//Persist changes to database
await _ctx.SaveChangesAsync(cancellationToken);
于 2019-06-14T17:23:30.277 に答える