Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare two lists of object for new, changed, updated on a specific property

I've been trying and failing for a while to find a solution to compare to lists of objects based on a property of the objects. I've read other similar solutions but they were either not suitable (or I didn't understand the answer!).

Code is C#

I have a model that represents an image

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; }     
}

I have two lists of this model. One is the existing list, another is an updated list. I need to compare the two lists to see which have been removed, updated or are new.

I don't need to compare the whole object, just compare them on their property Id.

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

New

If compareList contains any AccommodationImageModel with Id=0 then they are new because new entries do not have an Id assigned yet.

To be deleted

If masterList contains any AccommodationImageModel with Ids that are Not in compareList then they are to be deleted, because they have been removed from the compareList and should be removed from the masterList. Therefore I need a list of the ones that need to be deleted.

To be updated

If newList and masterList have Id's that are the same then they are to be updated. Therefore I need a list of the ones that share the same ID, so I can them update them. I'm not too concerned if these models are identical and don't need updating as there will only be a small number per list so it doesn't matter much if they get updated even if they haven't changed.

Each of the three results needs to be returned as a List of AccommodationImageModel so that I can then carry out the appropriate update, remove, add.

Edit

I've added 3 test methods below with my chosen solution from ATM, showing its working implementation.

Test methods

[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);
    }
like image 684
user3313496 Avatar asked May 10 '14 13:05

user3313496


People also ask

How to compare two list data in Java?

Java provides a method for comparing two Array List. The ArrayList. equals() is the method used for comparing two Array List. It compares the Array lists as, both Array lists should have the same size, and all corresponding pairs of elements in the two Array lists are equal.

How to compare two list in Java using Stream?

You need to override equals() method in SchoolObj class. contains() method you will uses the equals() method to evaluate if two objects are the same. But better solution is to use Set for one list and filter in another list to collect if contains in Set. Set#contains takes O(1) which is faster.


2 Answers

Simple Linq

New

List<AccommodationImageModel> toBeAdded = compareList.Where(c=>c.Id==0).ToList();

To be deleted

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

To be updated

List<AccomodationImageModel> toBeUpdated = masterList.Where(c => compareList.Any(d => c.Id == d.Id)).ToList();
like image 167
The One Avatar answered Oct 03 '22 19:10

The One


Assuming that two models with the same Id are considered the same model, you can write a IEqualityComparer like this:

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();
    }
}

You can then use Linq to get the lists that you want:

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();

The first one just filters the items with an Id of 0, which are conisdered new. The second query returns the items in the masterList which are not in the compareList. The last query returns the items which are in both lists. This code compiles but is untested.

like image 31
NeddySpaghetti Avatar answered Oct 03 '22 19:10

NeddySpaghetti