1

我注意到在我的项目中,我们经常编写递归函数。

我的问题是:有没有办法为使用递归迭代的每个层次结构创建递归函数作为通用函数?

也许我可以使用一个委托来获取递归的根和结束标志?

有任何想法吗?

谢谢。

4

5 回答 5

1

我认为您想要的是一种以通用方式处理分层结构的方法(英语中定义的“通用”,不一定是.Net中定义的)。例如,当我需要获取 Windows 窗体中的所有控件时,这是我曾经写过的:

public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector)
{
    if (items == null)
        throw new ArgumentNullException("items");
    if (selector == null)
        throw new ArgumentNullException("selector");

    return SelectManyRecursiveInternal(items, selector);
}

private static IEnumerable<T> SelectManyRecursiveInternal<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector)
{
    foreach (T item in items)
    {
        yield return item;
        IEnumerable<T> subitems = selector(item);

        if (subitems != null)
        {
            foreach (T subitem in subitems.SelectManyRecursive(selector))
                yield return subitem;
        }
    }
}


// sample use, get Text from some TextBoxes in the form
var strings = form.Controls
                  .SelectManyRecursive(c => c.Controls) // all controls
                  .OfType<TextBox>() // filter by type
                  .Where(c => c.Text.StartWith("P")) // filter by text
                  .Select(c => c.Text);

另一个例子:一个Category类,其中每个都Category可以有ChildCategories(同样的方式 aControl有一个Controls集合)并假设它rootCategory直接或间接地是所有类别的父类:

// get all categories that are enabled
var categories = from c in rootCategory.SelectManyRecursive(c => c.ChildCategories)
                 where c.Enabled
                 select c;
于 2009-05-19T15:05:15.083 回答
1

我的问题是:有没有办法为使用递归迭代的每个层次结构创建递归函数作为通用函数?可能我可以使用获取递归的根和结束标志的委托吗?

是的 - 您唯一需要的是一个委托函数,它为每个元素计算一个子元素列表。当没有孩子返回时,该函数终止。

    delegate IEnumerable<TNode> ChildSelector<TNode>(TNode Root);

    static IEnumerable<TNode> Traverse<TNode>(this TNode Root, ChildSelector<TNode> Children) {
        // Visit current node (PreOrder)
        yield return Root;

        // Visit children
        foreach (var Child in Children(Root)) 
            foreach (var el in Traverse(Child, Children))
                yield return el;

    }

例子:

        static void Main(string[] args) {

        var Init = // Some path

        var Data = Init.Traverse(Dir => Directory.GetDirectories(Dir, "*", SearchOption.TopDirectoryOnly));

        foreach (var Dir in Data)
            Console.WriteLine(Dir);

        Console.ReadKey();
    }
于 2009-05-19T15:15:46.420 回答
0

我不确定您的问题到底是什么,但递归函数可以是通用的。对此没有任何限制。例如:

int CountLinkedListNodes<T>(MyLinkedList<T> input) {
   if (input == null) return 0;
   return 1 + CountLinkedListNodes<T>(input.Next);
}
于 2009-05-19T14:42:09.810 回答
0

一种更简单且通用的方法可能是缓存函数的结果并仅在结果已知时使用“真实”函数 - 这种方法的有效性取决于递归期间使用同一组参数的频率。

如果您了解 Perl,您应该查看以电子书形式提供的Higher-Order Perl的前 4 章,其中提出的想法与语言无关。

于 2009-05-19T14:55:49.457 回答
0

听起来您的解决方案可以成功使用Visitor Pattern

您可以通过创建分层访问者模式来创建访问者模式的特定变体。

在这里完全讨论有点复杂,但这应该让你开始进行一些研究。基本思想是你有一个知道如何遍历结构的类,然后你有一个知道如何处理特定节点的访问者类。您可以将树的遍历与节点的处理分开。

于 2009-05-19T15:03:11.377 回答