LINQ query with Distinct and Union

前端 未结 4 1525
[愿得一人]
[愿得一人] 2021-01-01 17:29

I currently have 2 queries that are returning lists of MyModel like this:

var q1 = ....
         select new MyModel()
         {
             TheData1 = ...
         


        
相关标签:
4条回答
  • 2021-01-01 17:48

    I think frenchie wants a list of MyModel back instead of just the TheUniqueID.

    You need to create a MyModelTheUniqueIDComparer class and pass a new instance of it as a second argument into Union:

    class MyModelTheUniqueIDComparer : IEqualityComparer<MyModel>
    {
        public bool Equals(MyModel x, MyModel y)
        {
            return x.TheUniqueID == y.TheUniqueID;
        }
    
        // If Equals() returns true for a pair of objects 
        // then GetHashCode() must return the same value for these objects.
    
        public int GetHashCode(MyModel myModel)
        {
            return myModel.TheUniqueID.GetHashCode();
        }
    }
    

    Then you can call to get the result:

    var result = q1.Union(q2, new MyModelTheUniqueIDComparer());
    

    See http://msdn.microsoft.com/en-us/library/bb358407.aspx for a more details.

    Update:

    Try this:

    public class A
    {
        public string TheData1 { get; set; }
        public string TheData2 { get; set; }
        public string UniqueID { get; set; }
    }
    
    public class AComparer : IEqualityComparer<A>
    {
    
        #region IEqualityComparer<A> Members
    
        public bool Equals(A x, A y)
        {
            return x.UniqueID == y.UniqueID;
        }
    
        public int GetHashCode(A obj)
        {
            return obj.UniqueID.GetHashCode();
        }
    
        #endregion
    }
    

    And test with this:

    var listOfA = new List<A>();
    var q1 = from a in listOfA
                     select new A()
                 {
                     TheData1 = "TestData",
                     TheData2 = "TestData",
                     UniqueID = a.UniqueID
                 };
    
    var anotherListOfA = new List<A>();
    var q2 = from a in anotherListOfA
                     select new A()
                     {
                         TheData1 = "TestData",
                         TheData2 = "TestData",
                         UniqueID = a.UniqueID
                     };
    
    q1.Union(q2, new AComparer());
    

    Make sure you have using System.Linq;

    0 讨论(0)
  • 2021-01-01 17:49

    Inefficient single line answer with no IEqualityComparerer

    Using MoreLinq source code as inspiration, this will give a unique list:

    Short answer (the OrderBy isn't necessary but if not used the answer comes out as 2,3,6,9,11,4,7,12):

    var concattedUniqueList = theUniqueIDList1.Concat(theUniqueIDList2)
                .GroupBy(f=>f.UniqueID, f=>f).Select(g => g.First()).OrderBy(f=>f.UniqueID);
    

    Complete answer:

    //INPUT
    //theUniqueIDList1 = 2,3,6,9,11 
    //theUniqueIDList2 = 2,4,7,9,12
    //OUTPUT
    //2,3,4,6,7,9,11,12
    public class MyModel
    {
        public string TheData1 { get; set; }
        public string TheData2 { get; set; }
        public int UniqueID { get; set; }
    }
    
    public static void GroupByEx1()
        {
            // Create a list of Models.
            List<MyModel> theUniqueIDList1 =
                new List<MyModel>{  new MyModel { TheData1="Barley",    UniqueID=2 },
                                        new MyModel { TheData1="Boots",     UniqueID=3 },
                                        new MyModel { TheData1="Whiskers",  UniqueID=6 },
                                        new MyModel { TheData1="Daisy",     UniqueID=9 },
                                        new MyModel { TheData1="Preti",     UniqueID=11 } };
            List<MyModel> theUniqueIDList2 =
                new List<MyModel>{  new MyModel { TheData1="Barley",    UniqueID=2 },
                                        new MyModel { TheData1="Henry",     UniqueID=4 },
                                        new MyModel { TheData1="Walsh",     UniqueID=7 },
                                        new MyModel { TheData1="Daisy",     UniqueID=9 },
                                        new MyModel { TheData1="Ugly",  UniqueID=12 } };
            
            var concattedUniqueList = theUniqueIDList1.Concat(theUniqueIDList2)
                .OrderBy(f=>f.UniqueID).GroupBy(f=>f.UniqueID, f=>f).Select(g => g.First());
    
            foreach (var item in concattedUniqueList)
            {
                Console.WriteLine("UniqueId: {0}({1})", item.UniqueID, item.TheData1);
            }
        }
        
    void Main()
    {
        GroupByEx1();               
        //2,3,4,6,7,9,11,12
    }
    

    Note: compared to using an IEqualityComparer for speed - 10000 times for each 698 ns for Concat 100 ns for IEqualityComparer

    developed in LinqPad

    0 讨论(0)
  • 2021-01-01 17:57

    Union creates an Enumerable with unique values from both collections. In other words, you don't need Distinct.

    edit: example of Union here

    edit2: forgot that it's not the list of UniqueIDs that you're concatenating. I removed the suggested code since it was wrong. You should be able to do a simple Union if you implement an IEqualityComparer, but that might be overkill.

    0 讨论(0)
  • 2021-01-01 18:01

    As was pointed out if you are combining the lists with .Union() you will have to define uniqueness by using the overload passing an IEqualityComparer for your type.

    var result = q1.Union(q2, myEqualityComparer);
    

    otherwise, and easier you could use DistinctBy( x=> x.TheUniqueId) from the MoreLinq project:

    var result = q1.Concat(q2).DistinctBy(c => c.TheUniqueID);
    
    0 讨论(0)
提交回复
热议问题