我一直在尝试并且失败了一段时间,找到一个解决方案来比较基于对象属性的对象列表。我已经阅读了其他类似的解决方案,但它们要么不合适(或者我不理解答案!)。
代码是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);
}
答案 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方法..
希望这会有所帮助..