根据变量更改对对象列表进行排序和更新

本文关键字:排序 更新 列表 对象 变量 | 更新日期: 2023-09-27 17:59:05

我正在研究一种算法来解决我遇到的问题,但我发现自己有点卡住了。场景如下:

我有一个对象,其中包含一个名为 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!

谁能帮忙?

谢谢

根据变量更改对对象列表进行排序和更新

让我们看看列表中元素的四种情况(当我们迭代它们时(。如果(为了简洁起见(我们认为old是移动的旧位置的项目,new是它的新位置,那么对于您列表中的项目,我们有以下情况(将它们画在纸上以明确这一点(。

  1. 当前项目是要移动的项目:直接移动它
  2. 当前项目的顺序是<new和><old:不要移动它>
  3. 当前项目的顺序是≥ new和<old:向右移动>
  4. 当前项目的顺序是≤ new和> old:向左移动
  5. 当前项目的顺序是> new和> old:不要移动它

当我们开始枚举时,我们知道要移动的项目最终会在哪里(在new(,但我们不知道它来自哪里(old(。但是,当我们在列表的开头开始枚举时,我们知道在每一步中它必须位于列表的更靠后的位置,直到我们实际看到它!所以我们可以使用一个标志(seen(来表示我们是否已经看到它。所以seen假意味着<old而真意味着>=old

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

此标志告诉我们当前项目是否为>= 。所以现在可以根据这些知识和上述规则开始分流东西了。(所以上面讨论中的newinputNewPosition,无论我们是之前还是之后old我们用我们的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
        }            
    }
}

说了这么多,对每次更改的集合进行排序可能更简单。默认的排序算法应该非常简洁,具有几乎排序的集合。

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

也就是说,问题要求是什么? 如果我将项目 #2 的顺序切换到 #5,#3 会发生什么? 它是留在原地,还是应该是#6?

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

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

此处理程序采用请求对象。请求具有 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);
相关文章: