Linq扩展方法,如何在集合中查找子递归

sus*_*ite 11 c# linq recursion extension-methods hierarchy

我已经熟悉了Linq但对扩展方法了解甚少,我希望有人可以帮助我.

所以我有这个分层集合伪代码,即:

class Product
  prop name
  prop type
  prop id
  prop List<Product> children
Run Code Online (Sandbox Code Playgroud)

我有一个产品列表产品列表.

有没有什么办法可以通过id用扩展方法在这个集合中查找产品?换句话说,我需要在层次结构中的某个位置使用一个项目.

Jay*_*Jay 17

这是一个通用的解决方案,一旦找到匹配,就会短路层次结构的遍历.

public static class MyExtensions
{
    public static T FirstOrDefaultFromMany<T>(
        this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector,
        Predicate<T> condition)
    {
        // return default if no items
        if(source == null || !source.Any()) return default(T);

        // return result if found and stop traversing hierarchy
        var attempt = source.FirstOrDefault(t => condition(t));
        if(!Equals(attempt,default(T))) return attempt;

        // recursively call this function on lower levels of the
        // hierarchy until a match is found or the hierarchy is exhausted
        return source.SelectMany(childrenSelector)
            .FirstOrDefaultFromMany(childrenSelector, condition);
    }
}
Run Code Online (Sandbox Code Playgroud)

要在你的情况下使用它:

var matchingProduct = products.FirstOrDefaultFromMany(p => p.children, p => p.Id == 27);
Run Code Online (Sandbox Code Playgroud)


dtb*_*dtb 8

您可以使用此扩展方法展平树结构:

static IEnumerable<Product> Flatten(this IEnumerable<Product> source)
{
    return source.Concat(source.SelectMany(p => p.Children.Flatten()));
}
Run Code Online (Sandbox Code Playgroud)

用法:

var product42 = products.Flatten().Single(p => p.Id == 42);
Run Code Online (Sandbox Code Playgroud)

请注意,这可能不是很快.如果您反复需要按ID查找产品,请创建字典:

var dict = products.Flatten().ToDictionary(p => p.Id);

var product42 = dict[42];
Run Code Online (Sandbox Code Playgroud)