1

TL;DR 版本:

有没有办法枚举两个仅由一个元素(可能是附加元素或缺失元素)不同的列表,并在匹配所有其他元素的同时判断哪个元素已更改?


我的类有一个List<View>属性,它是List<Model>通过构造函数注入的。每个都View将其各自包装Model为公共属性。

在同一范围内,有一个void Update(List<Model> newList)例程,它接收具有以下条件的另一个列表Model:它与List<Model>以前相同,加或减一个元素。这是因为Update每次在其他地方的数据绑定列表中添加或删除项目时都会调用它,并且应用程序一次只能添加/删除一个元素。

操作的动机Update,而不是简单地用新列表替换旧列表的模型(包装在视图中),是View存储状态,所以我想替换它们的模型,但保留它们的状态——它不存储在反正模型。

问题是:如果有新模型,我必须添加新视图,当相应模型不存在时,我必须删除相应视图,并且我必须将现有视图与其现有模型匹配,除了添加的元素或删除。我不确定该怎么做。

所以我正在考虑将列表第一个元素中的模型与新列表的第一个元素进行比较,如果它们匹配,则转到第二个元素,依此类推。在某一时刻,它们会有所不同,但这可能是因为添加了一个元素(然后剩余的元素将移动一个索引),或者由于删除了一个元素(在这种情况下,剩余的元素将向下移动,并且不同的元素实际上是列表中已经存在的元素)。

有什么明智的方法来判断第一个不同的元素是由于添加还是删除?

4

3 回答 3

4

您可以使用Except()扩展名,例如:

List<Model> models = new List<Model>();
List<View> views = new List<View>();

然后,您可以通过以下方式获得所需的添加/删除项目:

//If models.Count > views.Count
var addedModel = models.Except(views.Select(v => v.Model)).FirstOrDefault();

//If views.Count > models.Count
var modelToRemove = views.Select(v => v.Model).Except(models).FirstOrDefault();
var viewToRemove = views.Single(v => v.Model == modelToRemove);

也许您需要通过 aIEqualityComparer<Model>进行自定义比较。


如果列表是或可以根据某些标准排序,您可以按照您在问题中所说的操作,找到列表不同的索引:

//for simplicity sorts the lists according to some 'Id'
models.Sort((a, b) => a.Id.CompareTo(b.Id));
views.Sort((a, b) => a.Model.Id.CompareTo(b.Model.Id));

然后,获取比较值的索引:

var index = Enumerable.Range(0, Math.Min(models.Count, views.Count))
                      .First(i => !Model.Equals(models[i], views[i].Model));

//If models.Count > views.Count
var addedModel = models[index];

//If views.Count > models.Count
var viewToRemove = views[index];
于 2016-04-18T20:06:44.023 回答
2

就代码行而言,这不是最短的解决方案,但如果知道一次只能插入或删除一个元素但整个列表中的更改不止一个),则可以使用以下循环:

var i = 0;
var j = 0;

while(i < oldList.Count || j < newList.Count)
{
    if (i >= oldList.Count)
    {
        for(; j < newList.Count; j++)
        {
            Console.WriteLine("{0} added", newList[j]);
        }
        break;
    }
    if (j >= newList.Count)
    {
        for(; i < oldList.Count; i++)
        {
            Console.WriteLine("{0} removed", oldList[i]);
        }
        break;
    }

    if (oldList[i] == newList[j])
    {
        Console.WriteLine("{0} not changed", oldList[i]);
        i++;
        j++;
    }
    else if(j < (newList.Count - 1) && oldList[i] == newList[j+1])
    {
        Console.WriteLine("{0} added", newList[j]);
        j++;
    }
    else
    {
        Console.WriteLine("{0} removed", oldList[i]);
        i++;

    }
}

我认为,与解决方案相比,它具有以下优点Except

  • 可以找到不止一个变化
  • O(n+m) 最大复杂度
  • 更好地控制您如何找到更改:Except解决方案只能检查相等性,但您可以在此处检查某些模型属性是否更改而其他模型属性没有更改
于 2016-04-19T07:06:29.680 回答
0

如果你View像这样向你的项目添加一个动作状态 {None,Added,Updated,Deleted} 是很容易的

View
{
  ActionState State{get;set;}
}

然后你可以像这样从你的输入列表中查询

var changedElement= views.FirstOrDefault(x=> x.State != ActionState.None);

接下来,根据您可以从现有列表中添加/更新/删除相应视图的操作。

希望这有帮助。

于 2016-04-18T20:06:22.213 回答