Поиск в иерархическом списке рекурсивно - PullRequest
2 голосов
/ 15 ноября 2010

У меня есть иерархический список объектов. Предположим, что структура выглядит следующим образом:

  • корневой узел
    • Родительский узел
      • дочерний узел
    • Родительский узел
      • дочерний узел
    • Родительский узел
      • дочерний узел

Дочерние узлы могут иметь своих собственных потомков, но цель состоит в основном в поиске «родительских узлов». Итак, допустим, что класс родительского узла имеет свойство «Имя» - и пользователь вводит частичное имя, я хочу, чтобы все родительские узлы, имя которых содержит критерии поиска пользователя, были возвращены. По сути, это больше функциональность «фильтра», чем все остальное. Итак, я знаю, как это сделать, однако проблема, с которой я сталкиваюсь, заключается в том, что их ключевая цель - сохранять иерархическую структуру в такте. Другими словами, если есть один родительский узел, который соответствует критериям фильтра, я хочу, чтобы была возвращена структура ниже:

  • корневой узел
    • Родительский узел
      • дочерний узел
      1036 **

Мои текущие усилия дают только:

  • Родительский узел
    • дочерний узел

Я использую Linq. Любые предложения будут с благодарностью.

Спасибо!

Chris

Фрагмент кода ниже для текущей реализации фильтра:

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

Ответы [ 3 ]

5 голосов
/ 15 ноября 2010

Поскольку возвращаемый вами корневой узел НЕ совпадает с исходным корневым узлом (у него меньше дочерних узлов), вам потребуется создать новый корневой узел, содержащий только совпадающие дочерние элементы.

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

  return newRootNode;
0 голосов
/ 15 ноября 2010

Есть несколько вещей, которые вы можете сделать здесь.

  1. Вы можете создать копию основной структуры и вернуть ее из фильтра (как можно более мелкое копирование, но вам придется глубоко копировать ссылки между узлами)
  2. Вы можете расширить свои узлы, чтобы понять, были ли они отфильтрованы или нет (то есть IsFilteredOut, ChildrenUnfilteredGet () и т. Д.), А затем отобразить «отфильтрованное» дерево.
  3. Вы можете сохранить список отфильтрованных узлов (черный или белый список) и затем ссылаться на него при отображении дерева (это включает в себя наименьшее количество изменений кода, но наибольшую вычислительную мощность).
0 голосов
/ 15 ноября 2010

Из памяти (может содержать опечатки) и на основании незнания вашего кода:

var filteredList = myRootNode.CollectionOfParentNodes.Where(p => p.Name.Contains(searchCriteriaString)).ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...