Sean
Sean

Reputation: 907

Finding Unique Objects between collections

I have a test where I have two lists created. One represents data that I have gone and collected from a source (of which I have no control over) and the other representing a known data already in my repository.

They look like this:

var newAccounts = new[]
{
    new Account
    {
        Id = 1,
        SA_ID = 1,
        SA_Name = "Sa_Name1",
        RelationshipType = "new",
        LE_ID = 1,
        LE_GroupID = 1,
        SiteID = 1,
        MinDate = DateTime.Now.AddDays(-1),
        MaxDate = DateTime.Now.AddDays(1),
        DaysOn = 1,
        Child1 = new List<Child1>{ new Child1
            {
                SiteID = 1,
                MaxDate = DateTime.Today.AddDays(7),
                MinDate = DateTime.Today.AddDays(1),
            }
        },
        Child2 = new List<Child2>
        {
            new Child2
            {
                SA_ID = 1,
                LastUpdate = DateTime.Now.AddDays(-1),
                CommentText = "Account added",
                Status = AccountStatus.AccountAdded.ToString(),
            }
        }
    },
    new Account
    {
        Id = 2,
        SA_ID = 2,
        SA_Name = "Sa_Name2",
        RelationshipType = "new",
        LE_ID = 2,
        LE_GroupID = 2,
        SiteID = 2,
        MinDate = DateTime.Now.AddDays(-2),
        MaxDate = DateTime.Now.AddDays(2),
        DaysOn = 2,
    },
    new Account
    {
        Id = 3,
        SA_ID = 3,
        SA_Name = "Sa_Name3",
        RelationshipType = "new",
        LE_ID = 3,
        LE_GroupID = 3,
        SiteID = 3,
        MinDate = DateTime.Now.AddDays(-3),
        MaxDate = DateTime.Now.AddDays(3),
        DaysOn = 3,
    }
};

var knownAccounts = new[]
{
    new Account
    {
        Id = 1,
        SA_ID = 1,
        SA_Name = "Sa_Name1",
        RelationshipType = "new",
        LE_ID = 1,
        LE_GroupID = 1,
        SiteID = 1,
        MinDate = DateTime.Now.AddDays(-1),
        MaxDate = DateTime.Now.AddDays(1),
        DaysOn = 1,
        Child1 = new List<Child1>{ new Child1
            {
                SiteID = 1,
                MaxDate = DateTime.Today.AddDays(7),
                MinDate = DateTime.Today.AddDays(1),
            }
        },
        Child2 = new List<Child2>
        {
            new Child2
            {
                SA_ID = 1,
                LastUpdate = DateTime.Now.AddDays(-1),
                CommentText = "Account added",
                Status = AccountStatus.AccountAdded.ToString(),
            }
        }
    }
};

In my unit tests I am wanting to strip out Account ID 1 from newAccounts so I'm only left with 2 entries in my collection. These are my attempts thus far:

public List<T> ReturnUniqueEntriesList<T>(List<T> newAccounts, List<T> knownAccounts)
{
    var a = knownAccounts.Intersect(newAccounts).ToList();

    var listA = newAccounts.Except(knownAccounts).ToList();
    var listB = knownAccounts.Except(newAccounts).ToList();

    var result = listB.Intersect(listA).ToList();

    return result;
}  

When I run this the final result is 0. a also returns 0 and listA & listB simply return their respective objects.

What is it that I'm doing wrong / missing here? Any help would be appreciated

Upvotes: 1

Views: 48

Answers (1)

Caius Jard
Caius Jard

Reputation: 74680

Override Equals and GetHashcode for Account so that they don't rely on the default implementations (memory address of the object). This means the C# will be able to equate them properly when executing an Except.

For example:

public class Account{

    public override bool Equals(object other){
      return other is Account a && a.Id == this.Id; //nb; is returns false if other is a null, even if it is an Account
    }

    public override int GetHashCode(){
      return Id.GetHashCode();
    }
}

As it is, the following two accounts are very different:

var a = new Account { Id = 1 };
var b = new Account { Id = 1 };

..because they live at different memory addresses.

By overriding Equals so that it compares the Id of the other, regardless the other properties, you can then essentially realize the situation you seem to describe of "two account objects with the same ID are equivalent"

If other properties factor into the decision, add those too. Hashcode.Combine is a useful method to combine several hashcodes for the puzzle of getting multiple properties' hashcodes to produce a suitable new signle hashcode - https://learn.microsoft.com/en-us/dotnet/api/system.hashcode.combine?view=net-5.0

Upvotes: 3

Related Questions