web-dev-qa-db-ja.com

特定のプロパティで新規、変更、更新されたオブジェクトの2つのリストを比較する

私はしばらくの間、オブジェクトのプロパティに基づいてオブジェクトのリストと比較するソリューションを見つけるために失敗してきました。他の同様のソリューションを読みましたが、どちらも適切ではありませんでした(または私は答えを理解していませんでした!)。

コードは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; }     
}

このモデルの2つのリストがあります。 1つは既存のリスト、もう1つは更新されたリストです。 2つのリストを比較して、削除、更新、または新規のリストを確認する必要があります。

オブジェクト全体を比較する必要はありません。プロパティIDで比較するだけです。

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

新着

CompareListにId = 0のAccommodationImageModelが含まれている場合、新しいエントリにはまだIDが割り当てられていないため、それらは新しいものです。

削除する

MasterListに、compareListにないIDを持つAccommodationImageModelが含まれている場合、それらは、compareListから削除されており、masterListから削除する必要があるため、削除されます。したがって、削除する必要があるもののリストが必要です。

更新する

NewListとmasterListに同じIDがある場合、それらは更新されます。したがって、同じIDを共有するもののリストが必要なので、それらを更新できます。これらのモデルが同一で、更新の必要がないかどうかはあまり心配していません。リストごとに数が少ないため、変更されていなくても更新されても問題はありません。

3つの結果のそれぞれをAccommodationImageModelのリストとして返す必要があるため、適切な更新、削除、追加を実行できます。

編集する

以下の3つのテスト方法を、ATMから選択したソリューションと共に追加し、実際の実装を示します。

試験方法

[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);
    }
17
user3313496

シンプルな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();
24
The One

同じIdを持つ2つのモデルが同じモデルと見なされるとすると、次のように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();

1つ目は、Idが0のアイテムをフィルターするだけで、新しいアイテムと見なされます。 2番目のクエリは、masterListにない項目をcompareListに返します。最後のクエリは、両方のリストにあるアイテムを返します。 このコードはコンパイルされますが、テストされていません。

4
Ned Stoyanov

簡単な方法の1つは、your 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)はマスターリスト内の新しいアイテムを挿入するためのメソッドです。

また、マスターリストからの削除とマスターリストへの挿入を行う必要があることに気付いたかもしれませんafterマスターリストをループしました!

0
MrPaulch
    ///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つのリストをマスターリストおよび一時リストとして使用する場合は、一時リストを反復して、各一時リスト項目でCheckStateメソッドを使用できます。

お役に立てれば..

0
sihirbazzz