Bhav
Bhav

Reputation: 2195

Join two lists of different objects and create a new list

I've got two lists of different objects.

List<ObjA> objAs = new List<ObjA>();
List<ObjB> objBs = new List<ObjB>();

They have the following class structures.

public class ObjA
{
    public int Id;
    public int ObjBId;
}

public class ObjB
{
    public int Id;
    public string Title;
}

Joining objA's ObjBId property to ObjB's Id property, I want to create a list of ObjA's Ids alongside ObjB's Titles. Something like this:

List<int, string> output = new List<int, string>();
// where int = ObjA's Id, string = ObjB's Title

How can I do this in LINQ? Are there any alternative than using Concat and creating a wrapper class?

Upvotes: 2

Views: 6769

Answers (4)

Damian70
Damian70

Reputation: 358

You can use a join and return a list

var result = (from a in objAs
    join b in objBs on a.ObjBId equals b.Id
    select new
    {
       a.ObjBId,
       b.Title
    }).ToList();

Upvotes: 2

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23228

You can use Join method and return a result as list of named tuples List<(int, string)> (available beginning with C# 7), becuase List<int, string> isn't a valid C# declaration.

var output = objAs.Join(objBs, a => a.ObjBId, b => b.Id, (a, b) => (a.Id, b.Title)).ToList();

You may also use anonymous objects instead of tuples, e.g. (a, b) => new { a.Id, b.Title}

Upvotes: 4

Harald Coppoolse
Harald Coppoolse

Reputation: 30464

So for every element of objAs, you want to take the Id, and if an object with the same Id is in objBs, you want the Id from objA and the title from objB.

In fact, since the Id of objA and objB are equal, you don't care if you take the Id from objA or from objB.

You didn't write what you want if there is no item in objBs with the same Id. Let's assume you want null in that case.

var result = objAs.GroupJoin(objBs,  // GroupJoin A with B
    objA => objA.Id,                 // from every element in A take the Id
    objB => objB.Id,                 // from every element in B take the Id

    // ResultSelector: take all elements of A, each with the matching elements from B
    (objA, matchingObjBs) => new
    {
        Id = objA.Id,
        Title = matchingObjBs.Select(objB => objB.Title).FirstOrDefault(),
    });

The nice thing about GroupJoin, is that you also get the element from A that have no matching B. And if there are more than one matching item in B, you take the first one.

If you don't want the items from A that have no matching Id in B, it is enough to take only the elements from B that have an Id in A:

var idsA = objAs.Select(objA => objA.Id);
var result = objBs.Where(objB => idsA.Contains(objB.Id));

Upvotes: 0

Anu Viswan
Anu Viswan

Reputation: 18155

Enumerable.Join should help you in this.

var result = objAs.Join(objBs,x=>x.ObjBId,y=>y.Id,(x,y)=>new {x.Id,y.Title})
                  .ToList();

Upvotes: 2

Related Questions