Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - Linq with two Lists

Tags:

c#

linq

I've got 2 classes which are connected together via an ID:

public class A {
    public int AID;
    public string Name;
}

public class B {
    public int BID;
    public int AID;
}

Now I want to filter my listB to get all B where A's Name is euqals the parameter name:

List<A> listA = ...;
List<B> listB = ...;

public List<B> Filter(string name) {
    var list = listB.Where(**... A.Name == name ...**).ToList();
    return list;
}

I don't know how to filter listB with the parameter I defined above. Maybe someone can help me figuring it out.

Thanks!

like image 677
DirtyNative Avatar asked Apr 25 '18 11:04

DirtyNative


Video Answer


2 Answers

Use Join and Where. I prefer the query syntax with joins:

IEnumerable<B> bs = 
    from a in listA
    join b in listB on a.AID equals b.AID
    where a.Name == name
    select b;
List<B> list = bs.ToList();

Another way which avoids duplicate B's (if it's a 1-to-many relationship) is using a lookup:

ILookup<int, string> aNameLookup = listA.ToLookup(a => a.AID, a => a.Name);
List<B> list = listB.Where(b => aNameLookup[b.AID].Contains(name)).ToList();
like image 193
Tim Schmelter Avatar answered Oct 05 '22 03:10

Tim Schmelter


Although you could filter a list of Bs using b.AID linear search, it would be inefficient:

return listB.Where(b => listA.FirstOrDefault(a => a.AID == b.AID)?.Name == name);

A better approach would be to place entries from listA into a Dictionary<int,A>, and use dictionary lookup by b.AID:

IDictionary<int,A> dictA = listA.ToDictionary(a => a.AID);
return listB.Where(b => dictA.TryGetValue(b.AID, out var a) && a.Name == name);

I would highly recommend keeping As in dictA rather than listA, because it would let you avoid rebuilding the dictionary for each query.

like image 20
Sergey Kalinichenko Avatar answered Oct 05 '22 01:10

Sergey Kalinichenko