比较两个对象列表,以便在特定属性上进行更新,更改,更新

时间:2014-05-10 13:04:36

标签: c# list object compare models

我一直在尝试并且失败了一段时间,找到一个解决方案来比较基于对象属性的对象列表。我已经阅读了其他类似的解决方案,但它们要么不合适(或者我不理解答案!)。

代码是C#

我有一个代表图像的模型

public class AccommodationImageModel
{
    public int Id { get; set; }
    public string Path { get; set; }
    public string Caption { get; set; }
    public string Description { get; set; }
    public bool CoverImage { get; set; }
    public bool Visible { get; set; }     
}

我有两个这个模型的列表。一个是现有列表,另一个是更新列表。我需要比较两个列表,看看哪些已删除,更新或是新的。

我不需要比较整个对象,只需在它们的属性Id上进行比较。

List<AccommodationImageModel> masterList;
List<AccommodationImageModel> compareList;

如果compareList包含Id = 0的任何AccommodationImageModel,则它们是新的,因为新条目尚未分配Id。

待删除

如果masterList包含任何不在compareList中的Ids的AccommodationImageModel,那么它们将被删除,因为它们已从compareList中删除,应该从masterList中删除。因此,我需要一个需要删除的列表。

待更新

如果newList和masterList具有相同的Id,那么它们将被更新。因此,我需要一个共享相同ID的列表,所以我可以更新它们。我不太关心这些模型是否相同且不需要更新,因为每个列表只会有一个小数字,所以即使它们没有改变它们也会更新并不重要。

三个结果中的每一个都需要作为AccommodationImageModel列表返回,以便我可以执行相应的更新,删除,添加。

修改

我已经使用我选择的ATM解决方案添加了下面的3种测试方法,显示了它的工作实现。

测试方法

[TestMethod]
    public void Test_Deleted_Image()
    {
        // set up the masterList
        List<AccommodationImageModel> masterList = new List<AccommodationImageModel>();
        masterList.Add(new AccommodationImageModel { Id = 1 });
        masterList.Add(new AccommodationImageModel { Id = 2 });

        // set up the compare list
        List<AccommodationImageModel> compareList = new List<AccommodationImageModel>();
        compareList.Add(new AccommodationImageModel { Id = 1 });
        compareList.Add(new AccommodationImageModel { Id = 3 });
        compareList.Add(new AccommodationImageModel { Id = 0 });

        // get the deleted models
        List<AccommodationImageModel> result = masterList.Where(c => !compareList.Any(d => d.Id == c.Id)).ToList();

        // result should hold first model with id 2
        Assert.AreEqual(2, result.FirstOrDefault().Id);
    }

    [TestMethod]
    public void Test_Added_Image()
    {
        // set up the masterList
        List<AccommodationImageModel> masterList = new List<AccommodationImageModel>();
        masterList.Add(new AccommodationImageModel { Id = 1 });
        masterList.Add(new AccommodationImageModel { Id = 2 });

        // set up the compare list
        List<AccommodationImageModel> compareList = new List<AccommodationImageModel>();
        compareList.Add(new AccommodationImageModel { Id = 1 });
        compareList.Add(new AccommodationImageModel { Id = 3 });
        compareList.Add(new AccommodationImageModel { Id = 0 });

        // get the added models
        List<AccommodationImageModel> result = compareList.Where(c => c.Id == 0).ToList();

        // result should hold first model with id 0
        Assert.AreEqual(0, result.FirstOrDefault().Id);
    }

    [TestMethod]
    public void Test_Updated_Image()
    {
        // set up the masterList
        List<AccommodationImageModel> masterList = new List<AccommodationImageModel>();
        masterList.Add(new AccommodationImageModel { Id = 1 });
        masterList.Add(new AccommodationImageModel { Id = 2 });

        // set up the compare list
        List<AccommodationImageModel> compareList = new List<AccommodationImageModel>();
        compareList.Add(new AccommodationImageModel { Id = 1 });
        compareList.Add(new AccommodationImageModel { Id = 3 });
        compareList.Add(new AccommodationImageModel { Id = 0 });

        // get the updated models
        List<AccommodationImageModel> result = masterList.Where(c => compareList.Any(d => c.Id == d.Id)).ToList();

        // result should hold first model with id 1
        Assert.AreEqual(1, result.FirstOrDefault().Id);
    }

4 个答案:

答案 0 :(得分:20)

简单的Linq

List<AccommodationImageModel> new = compareList.Where(c=>c.id==0).ToList();

待删除

List<AccomodationImageModel> deleted = masterList.Where(c => !compareList.Any(d => c.id == d.id)).ToList();

待更新

List<AccomodationImageModel> toBeUpdated = masterList.Where(c => compareList.Any(d => c.id == d.id)).ToList();

答案 1 :(得分:4)

假设具有相同Id的两个模型被视为相同模型,您可以像这样编写IEqualityComparer

public class AccommodationImageModelComparer : IEqualityComparer<AccommodationImageModel>
{
    public bool Equals(AccommodationImageModel x, AccommodationImageModel y)
    {
        if(x == null && y == null)
           return true;

        return x.Id == y.Id;
    }

    public int GetHashCode(AccommodationImageModel model)
    {
        return model.Id.GetHashCode();
    }
}

然后,您可以使用Linq获取所需的列表:

var comparer = new AccommodationImageModelComparer();

var newItems = compareList.Where (l => l.Id == 0).ToList();
var toBeDeleted = masterList.Except(compareList, comparer).ToList();
var toBeUpdated = masterList.Intersect(compareList, comparer).ToList();

第一个只过滤Id为0的项目,这些项目是新的。第二个查询返回masterList中不在compareList中的项目。最后一个查询返回两个列表中的项目。 此代码编译但未经测试。

答案 2 :(得分:0)

一种简单的方法是覆盖==中的AccomodationImageModel运算符:

public static override bool operator ==(AccommodationImageModel a, AccommodationImageModel b)
{
    return a.Id == b.Id;
}

然后在比较时只需检查主列表和比较器列表,并删除主列表中那些在比较器列表中没有相同对象的那些:

List<AccomodationImageModel> rem = new List<AccomodationImageModel>;
List<AccomodationImageModel> newobj = new List<AccomodationImageModel>;
foreach(AccomodationImageModel a in compareList) {
          if(a.Id == 0) { // id == 0 => new item
                 newobj.Add(a); // add new item later
          } else {
                 // check those existing items as to whether they need to be updated or removed
                 bool match = false;
                 foreach(AccomodationImageModel b in masterList) {
                      if(a == b) match = true; // match found
                 }
                 if(!match) rem.Add(a); else Update(a); // will be removed or updated
          }
}
// now remove unmatched items
foreach(AccomodationImageModel a in rem) { masterList.Remove(a); }
foreach(AccomodationImageModel a in newobj) { AddNew(a); }

注意Update(AccomodationImageModel a)是更新某个项目的方法,而AddNew(AccomodationImageModel a)是您在主列表中检查新项目的方法。

另外,您可能已经注意到从主列表中删除并插入主列表<=> 后,您已经循环使用主列表!

答案 3 :(得分:0)

    ///If image is not in list then add the image to the list

public void AddNew (List<AccomodationImageModel> masterList, AccomodationImageModel theImage)
{
    masterList.Add(theImage);
}

    /// If Image is in List then change listitem with new one

public void Update (List<AccomodationImageModel> masterList, int OldOnesID, AccomodationImageModel theNew)
{
    masterList[OldOnesID] = theNew;
}

    /// If Image should delete then removes the image from list

public void Delete (List<AccomodationImageModel> imgList, AccomodationImageModel theImageToDelete)
{
    masterList.Remove(theImageToDelete);
}


    /// this method checks the image state and do the work

public void CheckState (List<AccommodationImageModel> masterList, AccomodationImageModel theImage, bool deleteIt)
{


       for(int i = 0; i < masterList.Count; i++)
       {

         if (deleteIt)
         {
            Delete(masterList, theImage);
         }

         else
         {
           if(theImage.ID == 0)
           {
             AddNew(masterList, theImage);
           }

           if(masterList[i].ID == theImage.ID)
           {
             Update(masterList, i, theImage);
           }
       }
}

如果您更喜欢使用2个列表作为主列表和临时列表,那么您可以简单地迭代临时列表,每个templist项目都使用CheckState方法..

希望这会有所帮助..