Reputation: 6476
I am currently developing an application that requires this senario.
Assuming I have this object
public class ObjectItem
{
public int Id {get;set;}
public int Name {get;set;}
public int Sex {get;set;}
public int Age {get;set;}
public string Complexion {get;set;}
}
If we now have two lists of this object
var studentWithAge = new List<ObjectItem>
{
new ObjectItem {Id = 1, Name = "John", Age = 2},
new ObjectItem {Id = 2, Name = "Smith", Age = 5},
new ObjectItem {Id = 3, Name = "Juliet", Age = 7},
};
var studentWithSexAndComplexion = new List<ObjectItem>
{
new ObjectItem {Id = 1, Name = "John", Sex = "Male", Complexion = "fair"},
new ObjectItem {Id = 2, Name = "Smith", Sex = "Male", Complexion = " "},
new ObjectItem {Id = 3, Name = "Juliet", Sex = "Female", Complexion = "Blonde"},
new ObjectItem {Id = 4, Name = "Shittu", Sex = "Male", Complexion = "fair"},
};
I want to merge these two lists into just one. The end result should look like this.
var CompleteStudentData=new List<ObjectItem>
{
new ObjectItem{Id=1,Name="John",Sex="Male", Complexion="fair",Age=2},
new ObjectItem{Id=2,Name="Smith",Sex="Male", Complexion=" ", Age=5},
new ObjectItem{Id=3,Name="Juliet",Sex="Female", Complexion="Blonde", Age=7},
new ObjectItem{Id=4,Name="Shittu",Sex="Male", Complexion="fair", Age=0},
}
How do i achieve this? Using Union
to merge the two list does not produce the desired result. I would appreciate your help.
Upvotes: 2
Views: 1850
Reputation: 134811
Since it's possible that your collections will not have a 1-to-1 correspondence, you would have to do a full outer join. See here for how you can compose it that way.
Here's one way you can get similar results.
Collect all the keys (the ids) from both collections, then perform a left join with each of the collections, then combine the results.
var ids = studentWithAge.Select(s => s.Id)
.Union(studentWithSexAndComplexion.Select(s => s.Id));
var query =
from id in ids
from sa in studentWithAge
.Where(sa => sa.Id == id)
.DefaultIfEmpty(new ObjectItem { Id = id })
from ssc in studentWithSexAndComplexion
.Where(ssc => ssc.Id == id)
.DefaultIfEmpty(new ObjectItem { Id = id })
select new ObjectItem
{
Id = id,
Name = sa.Name ?? ssc.Name,
Sex = ssc.Sex,
Age = sa.Age,
Complexion = ssc.Complexion,
};
Upvotes: 1
Reputation: 38094
.Net has a function which is concatenating collections:
var concatenatedCollection = StudentWithAge.Concat(StudentWithSexAndComplexion).ToList();
var StudentWithAge = new List<ObjectItem>()
{
new ObjectItem{Id=1,Name="John",Age=2},
new ObjectItem{Id=2,Name="Smith",Age=5},
new ObjectItem{Id=3,Name="Juliet",Age=7},
};
var StudentWithSexAndComplexion = new List<ObjectItem>()
{
new ObjectItem{Id=1,Name="John",Sex="Male", Complexion="fair"},
new ObjectItem{Id=2,Name="Smith",Sex="Male", Complexion=" "},
new ObjectItem{Id=3,Name="Juliet",Sex="Female", Complexion="Blonde"},
new ObjectItem{Id=4,Name="Shittu",Sex="Male", Complexion="fair"},
};
var concatenatedCollection = StudentWithAge.Concat(StudentWithSexAndComplexion).ToList();
Upvotes: -1
Reputation: 2108
var result = StudentWithAge.Join(StudentWithSexAndComplexion,
sa => sa.Id,
ssc => ssc.Id,
(sa, ssc) => new ObjectItem
{
Id = sa.Id,
Name = sa.Name,
Age = sa.Age,
Sex = ssc.Sex,
Complexion = ssc.Complexion
}).ToList();
Or, avoiding creation of new objects:
var result = StudentWithAge.Join(StudentWithSexAndComplexion,
sa => sa.Id,
ssc => ssc.Id,
(sa, ssc) =>
{
sa.Sex = ssc.Sex;
sa.Complexion = ssc.Complexion;
return sa;
}).ToList();
And if you want to add students presented only in the second list, than also:
result.AddRange(StudentWithSexAndComplexion.Where(ssc => !StudentWithAge.Any(sa => sa.Id == ssc.Id)));
Upvotes: 4