开发者

Better Linq Query for filtering Parent List with no Children

I have 2 Lists.

var adultList = new List<Dude>();
adultList.Add(new Dude() { ID = 2, Name = "Randy Marsh" });
adultList.Add(new Dude() { ID = 3, Name = "Jimbo Kern" }); // no kids
adultList.Add(new Dude() { ID = 4, Name = "Gerald Broflovski" });
adultList.Add(new Dude() { ID = 5, Name = "Stuart McCormick" });
adultList.Add(new Dude() { ID = 6, Name = "Liane Cartman" });
adultList.Add(new Dude() { ID = 7, Name = "Ned Gerblansky" }); // no kids

var childList = new List<Dude>();
childList.Add(new Dude() { ID = 8, Name = "Stan Marsh", ParentID = 2 });
childList.Add(new Dude() { ID = 9, Name = "Kyle Broflovski", ParentID = 4 });
childList.Add(new Dude() { ID = 10, Name = "Ike Broflovski", ParentID = 4 });
childList.Add(new Dude() { ID = 11, Name = "Kenny McCormick", ParentID = 5 });
childList.Add(new Dude() { ID = 12, Name = "Eric Cartman", ParentID = 6 });

I want a Linq query to return that returns any Dudes in the adultList that do NOT have any kids. The result list should also have no null entries (in sample above, should have a Count() of 2 and return 开发者_如何学Conly Jimbo and Ned).

var nullList = new List<Dude>();
nullList.Add(null);
var adultsWithNoChildren = adultList.GroupJoin(
  childList,
  p => p.ID,
  c => c.ParentID,
  (p, c) =>
  {
    if (c.FirstOrDefault() == null) return p;
    return null;
  })
  .Except(nullList);

Is this the best way to accomplish this? is there another Linq function or something else? I don't like the idea of having the nullList created, but that is the only ensure that the result list has an accurate count.

Thanks


My approach would be like this:

var adultNoChildren = (from adult in adultList
                   where !childList.Any(child => child.ParentID == adult.ID)
                   select adult).ToList();

This can also be done using the other LINQ Syntax, but I can never remember that :) (The nice thing about .Any is that it stops as soon as it finds a result, so the entire child list is only traversed for adults with no children)


If the lists have any size at all, I have to recommend a solution involving GroupJoin, due to hashjoin costing n+m, versus where!any costing n*m

IEnumerable<Dude> noKids =
  from adult in adultList
  join child in childList
  on adult.ID equals child.ParentID into kids
  where !kids.Any()
  select adult;

Or in method form

IEnumerable<Dude> noKids = adultList.GroupJoin(
     childList,
     adult => adult.ID,
     child => child.ParentID,
     (adult, kids) => new {Dude = adult, AnyKids = kids.Any() })
  .Where(x => !x.AnyKids)
  .Select(x => x.Dude);

Lastly, is Liane really a dude?


adultList.Where(x => !childList.Select(y => y.ParentID).Contains(x.ID));


var noKids = from adult in adultList
                join child in childList
                on adult.ID equals child.ParentID into g
                from item in g.DefaultIfEmpty()
                where item == null
                select adult;


var noKids = adultList.Where(a => !childList.Any(c => c.ParentID == a.ID));
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜