Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
605 views
in Technique[技术] by (71.8m points)

c# - How to use linq `Except` with multiple properties with different class?

I am trying to learn the Linq/Lambda expressions and was stuck at somewhere.

What I was Doing

I have created two classes with properties which have some common properties in them. The classes are like(It's test code).

class TestA
    {
        public int Id { get; set; }
        public int ProductID { get; set; }
        public string Category { get; set; }

        public TestA(int id, int procid, string category)
        {
            this.Id = id;
            this.ProductID = procid;
            this.Category = category;
        }
    }

    class TestB
    {
        public int ProductID { get; set; }
        public string Category { get; set; }

        public TestB(int procid, string category)
        {
            this.ProductID = procid;
            this.Category = category;
        }
    }

Then I created the two list for them as,

        List<TestA> testListA = new List<TestA>();
        List<TestB> testListB = new List<TestB>();
        TestA t1 = new TestA(1, 254, "ProductA");
        TestA t2 = new TestA(1, 236, "ProductA");
        TestA t3 = new TestA(1, 215, "ProductB");
        TestA t4 = new TestA(1, 175, "ProductB");
        TestA t5 = new TestA(1, 175, "ProductC");
        testListA.Add(t1);
        testListA.Add(t2);
        testListA.Add(t3);
        testListA.Add(t4);
        testListA.Add(t5);

        TestB tt1 = new TestB(254, "ProdcutA");
        TestB tt2 = new TestB(215, "ProductB");
        TestB tt3 = new TestB(175, "ProductC");
        testListB.Add(tt3);
        testListB.Add(tt2);
        testListB.Add(tt1);

Now for result I wanted t2 as it's ProductID match is not in the testListB And t4 as it has matching ProductID in testListB but don't have the same Category.
1) I need a List<A> of every record which: No longer has a ProductID held in the testListB

which I can get as ,

  testListA.Select(x => x.ProductID).Except(testListB.Select(x => x.ProductID ));

2)No longer has a record which has a matching ProductID and Category in testListB

which I Can get using,

   testListA.Where(a => testListB.Any(b => a.ProductID == b.ProductID && a.Category != b.Category));

**My Question **
Is it possible two make single linq expression to get result.I thought of using the implement IEqualityComparer but I am not sure how to implement the GetHashCode it for two different type of classes. So either combining the above query into single query or any other way to impliment custom Comparer for two different Type of classes. Or is there any other simple way?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have said that you need only these objects from testListA:

  • there is not matching ProductID in testListB
  • there is existing mathing ProductID, but with different Category

So, your filter must be:

!testListB.Any(b => a.ProductID == b.ProductID && a.Category == b.Category)

So, change your code as:

testListA.Where(a => !testListB.Any(b => a.ProductID == b.ProductID && a.Category == b.Category));

Second approach:

Or you can create a new List<TestA> from the second list:

 var secondListA = testListB.Select(x=> new TestA(){Category=x.Category, ProductID=x.ProductID}).ToList();

And then create your Comparer:

sealed class MyComparer : IEqualityComparer<TestA>
{
    public bool Equals(TestA x, TestA y)
    {
        if (x == null)
            return y == null;
        else if (y == null)
            return false;
        else
            return x.ProductID == y.ProductID && x.Category == y.Category;
    }

    public int GetHashCode(TestA obj)
    {
        return obj.ProductID.GetHashCode();
    }
}

And use Except() overload which produces the set difference of two sequences by using the specified IEqualityComparer<T> to compare values.:

var result = testListA.Except(secondListA, new MyComparer ()).ToList();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...