【问题标题】:Simplest way to Recurse Over Object Tree递归对象树的最简单方法
【发布时间】:2016-07-13 16:01:18
【问题描述】:

我有一个基类:

public abstract class BaseClass{ 
    public bool IsSelected {get; set;}   
}

具有代表层次结构的集合的派生类:

public class DerivedOne : BaseClass{
    public ObservableCollection<BaseClass> Children {get; set;}
}

另一个派生类:

public class DerivedTwo : BaseClass{

}

DerivedOne 根下查找 IsSelected 设置为 true 的所有元素的最简单方法是什么?

【问题讨论】:

    标签: c# algorithm recursion tree treeview


    【解决方案1】:

    你遗漏了一些需求细节,但我认为这样的事情应该可行:

    public IEnumerable<BaseClass> AllIsSelected(BaseClass root)
    {
        if (root.IsSelected)
        {
            yield return root;
        }
        var composite = root as DerivedOne;
        if (composite != null)
        {
            foreach (var v in composite.Children)
            {
                foreach (var x in AllIsSelected(v))
                {
                    yield return x;
                }
            }
        }
    }
    

    当然,如果你想要一个完整的列表,你可以构建列表而不是使用 'yield'。

    这与此处讨论的设计相同:IEnumerable and Recursion using yield return

    正如另一个答案所说,您可以使用 LINQ 稍微缩短它。此版本避免制作临时列表。

    public IEnumerable<BaseClass> AllIsSelected(BaseClass root)
        {
            if (root.IsSelected)
            {
                yield return root;
            }
            var composite = root as DerivedOne;
            if (composite != null)
            {
                foreach (var x in composite.Children.SelectMany(v => AllIsSelected(v)))
                {
                    yield return x;
                }
            }
        }
    

    【讨论】:

    • 如果其中一个孩子也是 DerivedOne,则此方法将忽略其孩子。据我了解这个问题,这些也应该被遍历。我猜你需要某种堆栈或递归。
    • @timcbaoth 谢谢,我编辑了代码以正确迭代孩子。
    【解决方案2】:

    最简单的方法是使用带有递归的 LINQ

    public IEnumerable<BaseClass> GetAllSelectedChildren(DerivedOne derivedOne)
    {
        return derivedOne.Children.SelectMany(GetAllSelected);
    }
    
    public IEnumerable<BaseClass> GetAllSelected(BaseClass baseClass)
    {
        var selected = new List<BaseClass>();
    
        if(baseClass.IsSelected)
        {
            selected.Add(baseClass);
        }
    
        var derivedOne = baseClass as DerivedOne;
        if(derivedOne != null)
        {
            selected.AddRange(GetAllSelectedChildren(derivedOne));
        }
    
        return selected;
    }
    

    【讨论】:

      【解决方案3】:

      使用简单的Linq

        return root.Children
                   .SelectMany(c => new[]{ c }.Concat(c.Children)) // flatten the structure including self node.
                   .Where(e => e.IsSelected) // filter selected items
                   .ToList();
      

      【讨论】:

      • 这会扫描树任意深度吗?我认为它只会再上一层。它还要求 rootDerivedOne (这实际上是要求中规定的限制)。更一般的情况是 root 可以是任何 BaseClass
      猜你喜欢
      • 1970-01-01
      • 2015-11-19
      • 1970-01-01
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      • 2017-08-07
      • 2021-04-10
      • 1970-01-01
      相关资源
      最近更新 更多