私のプロジェクトでは、再帰関数を頻繁に書いていることに気付きました。
私の質問は次のとおりです。再帰反復を使用している階層構造ごとに、再帰関数を汎用関数として作成する方法はありますか?
たぶん、再帰のルートと終了フラグを取得するデリゲートを使用できますか?
何か案は?
ありがとう。
私の質問は、再帰的反復を使用している各階層構造の総称関数として再帰関数を作成する方法はありますか?再帰のルートと終了フラグを取得するデリゲートを使用できる可能性がありますか?
はい-必要なのは、各要素の子のリストを計算するデリゲート関数だけです。子が返されない場合、関数は終了します。
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();
}
あなたが望むのは、階層構造を一般的な方法で操作する方法だと思います(英語で定義されている「一般的な」、必ずしも.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
クラス(a がコレクションを持つのと同じ方法) であり、それが直接的または間接的にすべてのカテゴリの親であると仮定します。Category
ChildCategories
Control
Controls
rootCategory
// get all categories that are enabled
var categories = from c in rootCategory.SelectManyRecursive(c => c.ChildCategories)
where c.Enabled
select c;
より簡単で一般的なアプローチは、関数の結果をキャッシュし、結果がわかっている場合にのみ「実際の」関数を使用することです。このアプローチの有効性は、再帰中に同じパラメーターのセットが使用される頻度に依存します。
Perl を知っている場合は、EBook として入手できるHigher-Order Perlの最初の 4 つの章を確認する必要があります。提示されるアイデアは言語に依存しません。
あなたのソリューションはVisitor Patternを正常に使用できるようです。
階層的な訪問者パターンを作成することで、訪問者パターンの特定のバリエーションを作成できます。
ここですべてを議論するのは少し複雑ですが、それでいくつかの研究を始めることができます. 基本的な考え方は、構造をトラバースする方法を知っているクラスがあり、特定のノードを処理する方法を知っているビジター クラスがあるということです。ツリーの走査をノードの処理と分離できます。
あなたの質問が何を求めているのか正確にはわかりませんが、再帰関数は一般的です。それに制限はありません。例えば:
int CountLinkedListNodes<T>(MyLinkedList<T> input) {
if (input == null) return 0;
return 1 + CountLinkedListNodes<T>(input.Next);
}