Select 第一个符合条件的对象或内部对象

Select the first object that match condition or an inner object

我有一个 class,其中包含相同 class 的内部列表, 例如:

class Foo 
{
   string SearchId;
   List<Foo> GroupedPackages
}

我要return第一个"foo"符合条件的实例,可以在主实例中,也可以在内部List中。

这是我目前所拥有的——它有点难看,但它有效:

Package = response.lst.Where(p => p.SearchId == SearchId || 
                                 (p.GroupedPackages != null &&
                                  p.GroupedPackages.Any(m => m.SearchId==SearchId)))
                                                   .FirstOrDefault();
if (Package != null)
{
    if (Package.SearchId != SearchId) 
    {

        Package = Package.GroupedPackages.FirstOrDefault(m => m.SearchId == SearchId);
    }
 }

其中 "response.lst" 是 foo 的列表,Package 是 foo。

我希望尽可能在一行 lambda 表达式中完成

这会在顶层或 GroupedPackages 中的任何 Foo 实例中选择具有指定 SearchId 的第一个 Foo

Package = response.lst
    .Concat(response.lst
        .Where(x => x.GroupedPackages != null)
        .SelectMany(x => x.GroupedPackages)
    )
    .FirstOrDefault(x => x.SearchId == SearchId); 

我首先向 Foo 添加一个函数来检查条件:

class Foo {
  public bool FulfillsCondition(int searchId) {
     return this.SearchId==searchId;
  }
}

然后添加一个函数来查找自己或者children

class Foo {
  public Foo FindItemToFulfillCondition(int searchId) {
     if (this.FulfillsCondition) return this;
     return GroupedPackages.FirstOrDefault(p => p.FulfillsCondition);
  }
}

那你就可以

response.lst.Where(p => p.FindItemToFulfillCondition != null);

您需要先将列表展平,然后再进行搜索。

以下是展平列表的方法:

Func<IEnumerable<Foo>, IEnumerable<Foo>> flatten = null;
flatten = fs =>
    from f0 in fs
    from f1 in new [] { f0, }.Concat(flatten(f0.GroupedPackages))
    select f1;

所以,如果我从这个结构开始:

var foos = new List<Foo>()
{
    new Foo()
    {
        SearchId = "Y",
        GroupedPackages = new List<Foo>()
        {
            new Foo() { SearchId = "X" },
            new Foo() { SearchId = "Z" },
            new Foo()
            {
                SearchId = "W",
                GroupedPackages = new List<Foo>()
                {
                    new Foo() { SearchId = "G" },
                    new Foo() { SearchId = "H" },
                }
            }
        }
    }
};

我可以这样压扁它:

flatten(foos);

结果枚举是这样的:

那么这样做就变得简单了:

var result = flatten(foos).Where(f => f.SearchId == SearchId).FirstOrDefault();