How to combine two lists based on a property?

I have two lists, one fake and one real, for example:

before

// fake (list 1) { ID = 1, Year = 2011, X = "" } , { ID = 2, Year = 2012, X = "" } , { ID = 3, Year = 2013, X = "" } // real (list 2) { ID = 35, Year = 2011, X = "Information" } , { ID = 77, Year = 2013, X = "Important" } 

I want to combine them in the search for the Year, the result should be:

after

 { ID = 35, Year = 2011, X = "Information" } , { ID = 2, Year = 2012, X = "" } , { ID = 77, Year = 2013, X = "Important" } 

He must remove items with the same year in the first list and add an item with the equivalent Year to the second list in the first list, keeping order.

How can I do this with Linq?

+7
source share
4 answers

You must do this using the "left join":

 from f in fake join r in real on f.Year equals r.Year into joinResult from r in joinResult.DefaultIfEmpty() select new { ID = r == null ? f.ID : r.ID, Year = f.Year, X = r == null ? fX : rX }; 
+9
source

Justin query is the most efficient way to do this, but if you are interested in saving identical objects (rather than creating new records from the query), you can do it this way:

 var combined = from f in fake let r = (from r1 in real where r1.Year == f.Year select r1).SingleOrDefault() select r ?? f; 
+5
source

Instead of defining a fake list yourself, try running Linq for it:

 Enumerable.Range(2011,3) //2011, 2012, 2013 //use the overload that provides a 0-based ordinal position of each element .Select(x,i=> new {ID = i+1, Year = x, X = String.Empty) //now you have your fake list; join with the "real" list based on Year fields, //taking the real element wherever it exists and the fake one otherwise .Join(real, l=>l.Year, r=>r.Year, (l,r) => r == null ? l : r); 

This will lead to an accurate set of results. Most likely, you will need to define a named type for the list items, since two separately defined anonymous types cannot be implicitly converted, even if they have the same types / member names.

+1
source

Using IEnumerable.Union and IEqualityComparer .

PS This will lead to a different result compared to the left union, if there were more elements in the real list (years not in the fake list). The left join does not return those results that may be the desired result (not clear from the OP).

 public class MyClass { public int ID {get; set;} public int Year {get; set;} public string X {get; set;} } public class MyClassEqualityComparer : IEqualityComparer<MyClass> { public bool Equals(MyClass x, MyClass y) { return x.Year == y.Year; } public int GetHashCode(MyClass obj) { return obj.ToString().ToLower().GetHashCode(); } } void Main() { var fake = new List<MyClass> { new MyClass { ID = 1, Year = 2011, X = "" } , new MyClass { ID = 2, Year = 2012, X = "" } , new MyClass { ID = 3, Year = 2013, X = "" } }; var real = new List<MyClass> { new MyClass { ID = 35, Year = 2011, X = "Information" } , new MyClass { ID = 77, Year = 2013, X = "Important" } }; var merged = real.Union(fake, new MyClassEqualityComparer()); } 
+1
source

All Articles