更好的Linq查询过滤没有子项的父列表

时间:2010-06-03 23:40:44

标签: c# linq

我有2个列表。

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 });

我想要一个Linq查询返回,返回没有任何孩子的adultList中的任何Dudes。结果列表也应该没有空条目(在上面的示例中,Count()应该为2,并且只返回Jimbo和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);

这是实现这一目标的最佳方法吗?是否有另一个Linq功能或其他? 我不喜欢创建nullList的想法,但这是唯一确保结果列表具有准确计数的。

由于

5 个答案:

答案 0 :(得分:5)

我的方法是这样的:

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

这也可以使用其他LINQ语法完成,但我永远不会记得:)(关于.Any的好处是它会在找到结果后立即停止,因此整个子列表只会被遍历没有孩子的成年人)

答案 1 :(得分:2)

如果列表有任何大小,我必须推荐一个涉及GroupJoin的解决方案,因为hashjoin花费n + m,而不是!任何成本核算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;

或以方法形式

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);

最后,Liane真的是个老兄吗?

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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;

答案 4 :(得分:1)

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