【问题标题】:Search Hierarchical List Recursively递归搜索分层列表
【发布时间】:2011-05-10 07:55:45
【问题描述】:

我有一个分层的对象列表。假设结构如下:

  • 根节点
    • 父节点
      • 子节点
    • 父节点
      • 子节点
    • 父节点
      • 子节点

子节点可以有自己的子节点,但目标基本上是搜索“父节点”。因此,假设父节点类有一个名为“名称”的属性 - 并且用户输入了部分名称,我希望返回名称中包含用户搜索条件的所有父节点。基本上,这更像是一种“过滤器”功能。所以,我知道如何做到这一点,但是,我遇到的问题是他们的关键目标是保持层次结构的完整。换句话说,如果有一个父节点匹配过滤条件,我希望返回下面的结构:

  • 根节点
    • 父节点
      • 子节点

我目前的努力只收获:

  • 父节点
    • 子节点

我正在使用 Linq。任何建议将不胜感激。

谢谢!

克里斯

下面的代码 sn-p 用于当前的过滤器实现:

FilteredReports = Reports.FirstOrDefault().Children.Cast<IHierarchicalResult>()
                                    .SelectRecursive(item => item.Children.Cast<IHierarchicalResult>())
                                    .Where(item => item.Name.ToLower().StartsWith(filterCriteria))
                                    .ToObservableCollection();

这是我正在使用的扩展方法:

public static IEnumerable<T> SelectRecursive<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren)
    {
        if (null == source)
        {
            throw new ArgumentNullException("source");
        }

        if (null == getChildren) return source;

        return SelectRecursiveIterator(source, getChildren);
    }

    private static IEnumerable<T> SelectRecursiveIterator<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> getChildren)
    {
        foreach (T item in source)
        {
            yield return item;

            IEnumerable<T> children = getChildren(item);
            if (null != children)
            {
                foreach (T child in SelectRecursiveIterator(children, getChildren))
                {
                    yield return child;
                }
            }
        }
    }

【问题讨论】:

  • 您能提供更多信息吗?您的分层列表属于哪种类型的集合?子节点是封装在父节点内,还是以树型结构与父节点相关?代码 sn-ps 不错!
  • 集合是一个 ObservableCollection。每个节点都有一个名为 Children 的属性 - 它是同一类的 IEnumerable 集合。所以为了保持这个要求简单,使用扩展方法或其他一些干净的方法,我可以过滤根节点的初始子节点,并且仍然保持根节点完好吗?
  • 我认为我需要有两个系列。一个集合是对象的原始集合,第二个集合是我的动态集合,代表过滤后的结果。我也不想假设我总是只有一个根节点。

标签: c# linq lambda


【解决方案1】:

凭记忆(可能包含拼写错误)并基于不知道您的代码:

var filteredList = myRootNode.CollectionOfParentNodes.Where(p => p.Name.Contains(searchCriteriaString)).ToList();

【讨论】:

  • 他想要的是树结构,而不是列表。
  • 好的,我看错了问题,回答得太快了。不包含原始根节点。 Hightechrider 的回答对我来说是正确的。
【解决方案2】:

由于您要返回的根节点与原始根节点不同(它的子节点较少),您需要创建一个仅包含匹配子节点的新根节点。

类似

  Node oldRootNode = ...
  List<Node> filteredChildren = oldRootNode.Children.Where(...).ToList();
  Node newRootNode = new Node {Name = oldRootNode.Name, Children = filteredChildren};

  return newRootNode;

【讨论】:

  • 我喜欢这个解决方案。如果您不介意复制根节点,并且只需要在第一个子集合进行过滤,我会选择这个。
【解决方案3】:

您可以在这里做一些事情。

  1. 您可以创建主结构的副本并将其从过滤器中返回(尽可能浅复制,但您必须深复制节点之间的链接)
  2. 您可以扩展您的节点以了解它们是否已被过滤(即 IsFilteredOut、ChildrenUnfilteredGet() 等),然后显示“过滤”树。
  3. 您可以存储过滤节点列表(黑名单或白名单),然后在显示树时参考该列表(这涉及最少的代码更改,但处理能力最强)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-19
    • 2014-03-06
    • 1970-01-01
    • 2015-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-30
    相关资源
    最近更新 更多