Search code examples
c#linq.net-core

In LINQ how to check all fields of a inner list in a list with all fields of a inner list in another list?


This is my model:

class A
{
    public string Value { get; set; }
    public int? bId { get; set; }
    public B b { get; set; }
}
class B
{
    public int Id { get; set; }
    public List<A> aList { get; set; }
    public B ()
    {
        aList = new List<A>();
    }
}

Now in my program I have two objects of b and want to compare both lists of a in the b type.

I have two lists of b:

bool checkingDuplicatedObjects(List<B> b1, List<B> b2)
{
    List<B> q = new List<B>();
    if (b1.Count != b2.Count)
        return false;
    for (var i = 0; i < b1.Count; i++)
    {
        var x = b1[i];
        var y = b2[i];
        q = (from n1 in x.aList
             from n2 in y.aList
             where n1.Value == n2.Value
             select x).ToList();
    }
    if (q.Count() > 0)
        return true;
    else
        return false;
}

But I think this code is not completely logical. Can you please help me?


Solution

  • Ok there are many ways of doing this

        bool CheckDup(List<B> b1, List<B> b2)
        {
    
            if (b1.Count != b2.Count)
            {
                return false;
            }
    
            for (int i = 0; i < b1.Count; i++)
            {
                B x = b1[i];
                B y = b2[i];
    
                var c = x.aList.Select(al => al.Value).ToList();
                var d = y.aList.Select(al => al.Value).ToList();
    
                bool isEqual = c.SequenceEqual(d);
    
                if (!isEqual)
                {
                    return false;
                }
            }
    
            return true;
        }
    

    But we can make this look better by adding IEqualityComparer<> to A

    class A: IEqualityComparer<A>
    {
        public string Value { get; set; }
        public int? bId { get; set; }
        public B b { get; set; }
    
        public bool Equals(A? a1, A? a2)
        {
            return a1?.Value == a2?.Value;
        }
    
        public int GetHashCode(A a)
        {
            throw new NotImplementedException();
        }
    }
    

    With the Method now looking like this

        bool CheckDup(List<B> b1, List<B> b2)
        {
    
            if (b1.Count != b2.Count)
            {
                return false;
            }
    
            for (int i = 0; i < b1.Count; i++)
            {
                B x = b1[i];
                B y = b2[i];
    
                bool isEqual = x.aList.SequenceEqual(y.aList);
    
                if (!isEqual)
                {
                    return false;
                }
            }
    
            return true;
        }
    

    Or we can go really wild and also add the interface to B

    class B : IEqualityComparer<B>
    {
        public int Id { get; set; }
        public List<A> aList { get; set; }
        public B()
        {
            aList = new List<A>();
        }
    
    
        public bool Equals(B? b1, B? b2)
        {
            return b1.aList.SequenceEqual(b2.aList);
        }
        public int GetHashCode(B b)
        {
            throw new NotImplementedException();
        }
    }
    

    With this further shortening the Method to this

    bool CheckDup(List<B> b1, List<B> b2)
    {
    
        if (b1.Count != b2.Count)
        {
            return false;
        }
    
    
        bool eq = b1.SequenceEqual(b2);
    
        return eq;
    }
    

    Now be mindful that SquenceEquals is also dependent on the order. So List [1 2 3] and [1 2 3] are the same but [1 2 3] and [2 1 3] are not. If you wanna ignore order then you would need to change some things.

    The first example would need to be changed to

        bool CheckDup(List<B> b1, List<B> b2)
        {
    
            if (b1.Count != b2.Count)
            {
                return false;
            }
    
            for (int i = 0; i < b1.Count; i++)
            {
                B x = b1[i];
                B y = b2[i];
    
                var c = x.aList.Select(al => al.Value).ToList();
                var d = y.aList.Select(al => al.Value).ToList();
    
                bool isEqual = c.All(d.Contains);
    
                if (!isEqual)
                {
                    return false;
                }
            }
    
            return true;
        }
    

    The Second to

        bool CheckDup(List<B> b1, List<B> b2)
        {
    
            if (b1.Count != b2.Count)
            {
                return false;
            }
    
            for (int i = 0; i < b1.Count; i++)
            {
                B x = b1[i];
                B y = b2[i];
    
                bool isEqual = x.aList.All(y.aList.Contains) && x.aList.Count == y.aList.Count;
    
                if (!isEqual)
                {
                    return false;
                }
            }
    
            return true;
        }
    

    And in the third we would need to change Bs Equals Method to

    public bool Equals(B? b1, B? b2)
    {
        return b1.aList.All(b2.aList.Contains) && b1.aList.Count == b2.aList.Count;
    }