Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare list of X to list of Y in C# by using generics?

I have 2 classes, X and Y. Both classes have same similar property like below.

class X
{
    public string T1 { get; set; }
    public string T2 { get; set; }
    public string T3 { get; set; }
}

class Y
{
    public string T1 { get; set; }
    public string T2 { get; set; }
    public string T3 { get; set; }

    public string O1 { get; set; }
}

I've couple hundreds classes similar to X and Y; similar structure, and I decide to create generic class for this problem.

I have list of X and Y and I want to compare them by T1; only 1 property, to find out which element exist on both list, which element exist only on X and only on Y.

How can I do this?

like image 392
Anonymous Avatar asked Dec 03 '22 04:12

Anonymous


2 Answers

The best thing to do is to first create an interface that contains T1 only. Then you inherit each class like X and Y from this interface. Now you can easily create your generic classes or any helper classes based on this interface.

Alternatively, you may use reflection, or if you use C# 4.0, you can use dynamic. Classic reflection is way to slow for (large) lists, so unless you cache your method calls, you shouldn't take that approach. C# 4.0 however, provided method caching through the DLR, which is sufficiently fast in most cases.

Alternatively (2): when you want to do this "right" and you want to compare the lists using standard mechanisms like LINQ, you should implement IComparable. You can combinee that with generics to create type-safety.

// the interface, inherit from IComparable
public interface IX : IComparable<IX>
{
    string T1 { get; set; }
}

// create one base class
class XBase : IX
{
    public string T1 { get; set; }
    public int CompareTo(IX obj)
    {
        return this.T1.equals(obj.T1);
    }
}

// inherit all others from base class
class X : XBase
{
    public string T2 { get; set; }
    public string T3 { get; set; }
}

class Y : XBase
{
    public string T2 { get; set; }
    public string T3 { get; set; }

    public strign O1 { get; set; }
}

There are many other ways. The last method above has the advantage of only once writing the logic for T1 and CompareTo, which saves from clutter and creates clarity in your code.

like image 80
Abel Avatar answered Mar 02 '23 16:03

Abel


I had a really hard time understanding the question. But I read it as "how can I find a diff between lists of these two objects based on their T1 value." However, like I said, this is a total guess as to what the actual question is.

Using linq here is a good start for you:

IEnumerable<string> intersectionT1s = listX.Select(x => x.T1).Intersect(listY.Select(y => y.T1);
IEnumerable<X> intersection = listX.Where(x => intersectionT1s.Contains(x.T1));
IEnumerable<X> onlyOnX = listX.Where(x => !listY.Any(y => y.T1 == x.T1));

I'll leave onlyOnY as an exercise for the reader.

Here is a generic intersection method which you can use:

public static class ExtensionMethods
{
    public static IEnumerable<TLeft> IntersectionOn<TLeft, TRight, TField>(this IEnumerable<TLeft> left,
        IEnumerable<TRight> right, Func<TLeft, TField> leftSelector, Func<TRight, TField> rightSelector)
    {
        var intersectionFields = left.Select(leftSelector).Intersect(right.Select(rightSelector));
        return left.Where(x => intersectionFields.Contains(leftSelector(x)));
    }
}

and the usage:

IEnumerable<X> intersection = listX.IntersectionOn(listY, x => x.T1, y => y.T1);
like image 22
tster Avatar answered Mar 02 '23 18:03

tster