使用LINQ在对象排序列表中查找空白吗?

时间:2019-02-26 15:56:47

标签: c# linq

问题: 我有一个wpf DataGrid,它绑定到自定义模型类中的对象列表。我需要满足以下要求:

  • 此列表中仅包含一定数量的模型(例如,假设有8个玩家的在线计算机游戏)
  • 每个模型都有自己的唯一ID
  • 可以在运行时将模型添加到列表或从列表中删除
  • 在初始化时,每个模型应从列表中获得最低的空闲ID
  • 我不想每次添加新模型时都在列表中进行迭代
  • 所有这些都需要在后端进行,所以我不能使用任何xaml代码(这也是为什么我没有设置wpf标记的原因)

我正在寻找类似于this question的东西,但是我很难将列表转换为与Enumerable.Except方法兼容的东西。

这是一个小例子:

型号:

public class MyModel
{
    public MyModel(int mID, string mName, string mScore)
    {
      ID = mID;
      Name = mName;
      Score = mScore;
    }
    public int ID;
    public string Name;
    public string Score;
  }

尝试将空闲ID最低的新模型添加到我的列表中

  List<MyModel> list = new List<MyModel>();
  list.Add(new MyModel(0, "Rodney", "189"));
  list.Add(new MyModel(1, "Janet", "169"));
  list.Add(new MyModel(2, "John", "110"));
  list.Add(new MyModel(3, "Samantha", "160"));
  list.Add(new MyModel(4, "Daniel", "156"));
  list.Add(new MyModel(5, "Jack", "89"));

  list.RemoveAll(x => x.ID == 1);
  var result = Enumerable.Range(list.Min(m => m.ID), list.Count).Except(list).First();
  list.Add(new MyModel(result, "Carolyn", "159")); //Should be 1

我可能必须使用某种lambda表达式,就像我在list.Min()方法中必须使用的那样,但是花了很长时间才能做到这一点。

4 个答案:

答案 0 :(得分:2)

问题是您比较两种不同类型的对象。 Enumerable.Range(list.Min(m => m.ID), list.Count)是0到5之间整数的枚举,当您使用Except(list)时,列表由MyModel个对象组成。

您可能要提取ID:

var result = Enumerable.Range(list.Min(m => m.ID), list.Count).Except(list.Select(m => m.ID)).First();

答案 1 :(得分:2)

为什么要编写复杂的代码?您希望数字大于列表中不存在的最低项目

 var result = list.Min(m => m.ID);
 while (list.Any(m => m.ID == result))
   result++;

这可能不是最快的代码,但是至少很清楚。

答案 2 :(得分:0)

要扩展评论者发布的内容,请使用SortedList,您可以使用它来跟踪免费ID。这样,您就不必寻找差距。当您向主列表中添加某些内容时,请从空闲列表中删除第一个整数,并将该值用作模型的ID。从主列表中删除模型后,将其ID添加到空闲列表中。

答案 3 :(得分:0)

  

我不想每次添加新模型时都在列表中进行迭代

实际上,这意味着您不能使用MinMaxExcept之类的Linq方法,因为它们会在您的后台进行迭代。

您应该记住的另一件事是RemoveAll还会遍历列表中的所有项目。因此,您需要更改两件事:首先(已经在Fabjan注释和工具包答案中提到过)是跟踪SortedList中所有已删除的标识符,其次是使用Dictionary<int, MyModel>通过密钥删除模型,这是O(1)的复杂度,而不是O(N)情况下的List

您可以使用以下Container类来封装此逻辑:

public class Container
{
    private readonly Dictionary<int, MyModel> items = new Dictionary<int, MyModel>();
    private readonly SortedList removedIds = new SortedList();
    private int maxId = 0;

    public int Add(MyModel model)
    {
        int id;
        if (removedIds.Count > 0)
        {
            id = (int) removedIds.GetByIndex(0);
            removedIds.RemoveAt(0);
        }
        else
        {
            id = maxId++;
        }

        model.ID = id;
        items.Add(id, model);
        return id;
    }

    public void RemoveById(int id)
    {
        if (!items.ContainsKey(id))
            throw new ArgumentException(); // or just return

        items.Remove(id);
        removedIds.Add(id, id);
    }
}