Поиск всех предков до идентификатора узла - PullRequest
2 голосов
/ 06 октября 2011

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

public IEnumerable<INode> Ancestors()
{
   var parent = this.Parent;
   while (parent != null)
   {
      yield return parent;
      parent = parent.Parent;
   }
}

Я думаю, я должен передать Func или Func для остановки / прерывания последовательности.

Какая это будет лучшая реализация? .Ta

Отредактировано: с учетом ответов ниже.Я думаю, что собираюсь сделать что-то более производительное, например:

 public IEnumerable<INode> Ancestors(Func<INode, bool> predicate)
 {
    var parent = this.Parent;
    while (parent != null)
    {
      if (predicate(parent))
      { 
         yield return parent;
      }
      else
      { 
         yield break; 
      }

      parent = parent.Parent;
    }
 }

Правильно ли я говорю, что ответ Джона создаст 2 счетчика?

Ответы [ 2 ]

4 голосов
/ 06 октября 2011

Как насчет:

var desiredNode = child.Ancestors().FirstOrDefault(node => node.Id == desiredId);

Это дает null, если нужный узел не может быть найден.

РЕДАКТИРОВАТЬ: Хорошо, если вам нужна полная последовательность снизу вверх, вы можете просто использовать:

var nodes = child.Ancestors().TakeUntil(node => node.Id == desiredId);

, где TakeUntil - это метод, подобный TakeWhile, но включающий последний узел, который соответствует предикату.Вы можете найти пример реализации в MoreLINQ .Если вы не возражаете против отсутствия проверки аргументов (которую обеспечивает MoreLINQ ), написать очень просто:

public static IEnumerable<T> TakeUntil<T>(this IEnumerable<T> source,
                                          Func<T, bool> predicate)
{
    foreach (T item in source)
    {
        yield return item;
        if (predicate(item))
        {
            yield break;
        }
    }
}

Вы могли бы создать функциональностьв метод Ancestors(), но он объединяет две обязанности в одну относительно сложную функцию, вместо того, чтобы иметь две простые функции, которые могут быть составлены с другими простыми функциями очень общим способом.

0 голосов
/ 06 октября 2011

Попробуйте это:

public IEnumerable<INode> Ancestors(Func<INode, bool> takeUntil)
{
   var parent = this.Parent;
   while (parent != null)
   {
      yield return parent;
      if (takeUntil(parent))
      {
         break;
      }
      parent = parent.Parent;
   }
}
...
var ancestors = node.Ancestors(n => n.Id == 123);
...