user1608132
user1608132

Reputation: 301

Join two lists with one to many relationship

I have two classes like so. One has a list of the other class and are linked by key1.

public class Alpha
{
    public key1 { get; set; }
    public List<Bravo> { //getter and setter }
}

public class Bravo
{
    public key1 { get; set; }
    public someProp { get; set; }
}

I have a method that gets two lists of Alpha and Bravo and I need to join them into one list of Alpha. Each Alpha has a one to many relationship with Bravo but now I have many Alpha. I know I could iterate through both lists but is there a faster way?

public List<Alpha> Join (List<Alpha> alphaList, List<Bravo> bravoList)
{
    //match each Bravo with it's corresponding Alpha
}

Example:

alphaList = { 
    item1 { key1 = 1, bravoList { } }
    item2 { key1 = 2, bravoList { } }
    item3 { key1 = 3, bravoList { } }
}

bravoList = {
    itemA { key1 = 1, someProp }
    itemB { key1 = 2, someProp }
    itemC { key1 = 2, someProp }
    itemD { key1 = 3, someProp }
    itemE { key1 = 3, someProp }
}

finalList = {
    item1 { key1 = 1, bravoList { itemA } }
    item2 { key1 = 2, bravoList { itemB, itemC } }
    item3 { key1 = 3, bravoList { itemD, itemE } }
}

Upvotes: 2

Views: 2906

Answers (3)

Tim Schmelter
Tim Schmelter

Reputation: 460228

You can use Enumerable.Join:

public List<Alpha> Join(List<Alpha> alphaList, List<Bravo> bravoList)
{
    return alphaList.Join(bravoList, a => a.key1, b => b.key1, (a,b) => a)
                    .ToList();
}

This will return a list of all Alphas which key1 is also in the list of Bravos.

Update:

public List<Alpha> Join(List<Alpha> alphaList, List<Bravo> bravoList)
{
    List<Alpha> finalList = alphaList
        .Select(a => new Alpha { 
             key1 = a.key1, 
             bravoList =  bravoList.Where(b => b.key1 == a.key1).ToList()
         }).ToList();
    return finalList;
}

Upvotes: 3

p.s.w.g
p.s.w.g

Reputation: 149040

According to your comments, the list of Bravo's on Alpha is pretty much extraneous since it's not being managed in any way by an ORM.

If you want to join, here's the simplest way to use it:

public IEnumerable<Tuple<Alpha, Bravo>> Join (IEnumerable<Alpha> alphaList, IEnumerable<Bravo> bravoList)
{
    return (from a in alphaList
            join b in bravoList on a.key1 equals b.key1
            select Tuple.Create(a, b))
           .ToList();
}

Since this is a many-to-one relationship, this will probably be more useful:

public Lookup<Alpha, Bravo> Join (IEnumerable<Alpha> alphaList, IEnumerable<Bravo> bravoList)
{
    return (from a in alphaList 
            join b in bravoList on a.key1 equal b.key1 into g
            select new { a, g })
           .ToLookup(x => x.a, x.g)
}

Notice the into clause; it allows you to grouped the joined items together. I then turn the groupings into a Lookup for easy access.

If you do want to keep the list on Alpha, there's probably no way to do this without either a foreach-loop or an awful lot of work building your own mini-ORM.

Upvotes: 1

Nikolay Kostov
Nikolay Kostov

Reputation: 16983

public class Helper
{
    public List<Alpha> Join(List<Alpha> alphaList, List<Bravo> bravoList)
    {
        return alphaList.Select(a => new Alpha() { key1 = a.key1, list = bravoList.Where(b => b.key1 == a.key1).ToList() }).ToList();
    }
}

public class Alpha
{
    public int key1 { get; set; }

    public List<Bravo> list { get; set; }
}

public class Bravo
{
    public int key1 { get; set; }

    public string someProp { get; set; }
}

Upvotes: 2

Related Questions