基于变量更改对对象列表进行排序和更新

时间:2013-02-14 17:36:55

标签: c# algorithm list int

我正在研究一种算法,它可以解决我遇到的问题,但我发现自己有点陷入困境。这是场景:

我有一个包含一个名为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!

有人可以帮忙吗?

由于

3 个答案:

答案 0 :(得分:3)

让我们看一下列表中元素的四种情况(当我们遍历它们时)。如果(为了简洁)我们将old作为移动旧位置且new作为其新位置的项目,我们对列表中的项目有以下情况(在纸上绘制出来)说清楚)。

  1. 当前项目是要移动的项目:直接移动
  2. 当前项目的订单是&lt; new和&lt; old:不要移动它
  3. 当前项目的订单≥new且&lt; old:向右移动
  4. 当前项目的订单为<new且&gt; old:向左移动
  5. 当前项目的订单是&gt; new和&gt; old:不要移动它
  6. 当我们开始枚举时,我们知道要移动的项目的最终位置(new),但我们不知道它来自哪里(old)。但是,当我们在列表的开头开始枚举时,我们知道每一步都必须在列表中进一步向下,直到我们真正看到它为止!所以我们可以使用一个标志(seen)来说明我们是否已经看过它。所以seen的错误意味着&lt; old,而true表示&gt; = old

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

    此标志告诉我们当前项目是否为&gt; = old 。所以现在可以根据这些知识和上述规则开始分流。 (上述讨论中new inputNewPositionold以及我们是seen之前还是之后我们用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 } } } 变量表示。)

    {{1}}

    说完所有这些之后,在每次更改时对集合进行排序可能更简单。默认的排序算法应该是非常糟糕的几乎排序的集合。

答案 1 :(得分:0)

您的问题不是很清楚,但对于要求,您可能最好在包含Order的对象上执行事件,并且可能有一个容器对象可以监视它。但是我怀疑你可能想重新考虑你的算法,如果是这样的话,因为它似乎是一个非常尴尬的方式来处理按顺序显示的问题。

那说,问题要求是什么?如果我将项目#2的顺序切换到#5,那么#3会发生什么?它是否仍然存在,或者它应该是#6?

答案 2 :(得分:0)

这是我解决问题的方法,但是我认为可能还有更聪明的出路。

我需要更新的对象是策略工作负载项。其中的每一个都有关联的优先级。不能有具有相同优先级的策略工作负载项目。因此,当用户更新优先级时,其他优先级需要相应地上移或下移。

此处理程序接受一个请求对象。该请求具有ID和优先级。

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

此类在以下代码中表示 request 对象。

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