Search code examples
c#lambdahashsetpredicateremoveall

Remove List items from List with Removeall Lambda Hashset


I'm using FileHelpers to parse 2 text files that contain active directory user information the Users class is defined as:

    [DelimitedRecord(",")]

public class Users
{
    public string LogonName;

    public string DisplayName;

    public string FirstName;

    public string LastName;

    public string SamAccountName;

    public string Password;

    public string Identity;

}

The CSV files contain LogonName,DisplayName,FirstName,LastName,SamAccountName,Password,Identity MM0123,Mothhair Mayeye,Mathhair,Mayeye,MM0123,secrtpwd,Group1

Most of the users in both files are identical. There are around 6500 records.

I'm expecting that after this runs:

        List<Users> UserListCur = new List<Users>();
        List<Users> UserListLR = new List<Users>();
        FileHelperEngine engine = new FileHelperEngine(typeof(Users));

        var records = engine.ReadFile(@"C:\\users.csv");
        var lrrecords = engine.ReadFile(@"C:\\lastrun.csv");

        foreach (Users record in records)
        {

            UserListCur.Add(record);
        }

        foreach (Users record in lrrecords)
        {

            UserListLR.Add(record);
        }


        UserListCur.RemoveAt(0);
        UserListLR.RemoveAt(0);


        var UserListLRhash = new HashSet<Users>(UserListLR);
        UserListCur.RemoveAll(x => UserListLRhash.Contains(x));

The entries from UserListLR should be removed from UserListCur but UserListCur is not changed. Most of the user entries are identical so I'm not sure why it's not removing any of them.


Solution

  • You must either override Equals(object) and GetHashCode() in users to define what makes two users equal or you must write a class that implements IEqualityComparer<Users> and pass that class in to the constructor of the HashSet you created.

    When you just use the default implementation of equality like your code currently does the only way two users will be considered equal is if Object.RefrenceEquals(user1, user2) returns true.

    Here is a example creating a comparer and passing it in.

    public sealed class UsersEqualityComparer : IEqualityComparer<Users>
    {
        public bool Equals(Users x, Users y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (ReferenceEquals(x, null)) return false;
            if (ReferenceEquals(y, null)) return false;
            if (x.GetType() != y.GetType()) return false;
            return string.Equals(x.LogonName, y.LogonName) && string.Equals(x.DisplayName, y.DisplayName) &&
                   string.Equals(x.FirstName, y.FirstName) && string.Equals(x.LastName, y.LastName) &&
                   string.Equals(x.SamAccountName, y.SamAccountName) && string.Equals(x.Password, y.Password) &&
                   string.Equals(x.Identity, y.Identity);
        }
    
        public int GetHashCode(Users obj)
        {
            if(ReferenceEquals(obj, null))
                throw new ArgumentNullException("obj");
    
            unchecked
            {
                var hashCode = (obj.LogonName != null ? obj.LogonName.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (obj.DisplayName != null ? obj.DisplayName.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (obj.FirstName != null ? obj.FirstName.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (obj.LastName != null ? obj.LastName.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (obj.SamAccountName != null ? obj.SamAccountName.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (obj.Password != null ? obj.Password.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ (obj.Identity != null ? obj.Identity.GetHashCode() : 0);
                return hashCode;
            }
        }
    }
    

    and your code changes to

        List<Users> UserListCur = new List<Users>();
        List<Users> UserListLR = new List<Users>();
        FileHelperEngine engine = new FileHelperEngine(typeof(Users));
    
        var records = engine.ReadFile(@"C:\\users.csv");
        var lrrecords = engine.ReadFile(@"C:\\lastrun.csv");
    
        foreach (Users record in records)
        {
    
            UserListCur.Add(record);
        }
    
        foreach (Users record in lrrecords)
        {
    
            UserListLR.Add(record);
        }
    
    
        UserListCur.RemoveAt(0);
        UserListLR.RemoveAt(0);
    
    
        var UserListLRhash = new HashSet<Users>(UserListLR, new UsersEqualityComparer());
        UserListCur.RemoveAll(x => UserListLRhash.Contains(x));