0

私は C# 構文に精通しているので、それを使用しますが、言語固有のものではありません。


Treeを調べて、それぞれで何かを行う ための API を提供したいとしましょうNode

解決策 1:ツリー内の各ノードで , およびvoid Visit(Tree tree, Action<Node> action)
tree呼び出します。action

解決策 2:各ノードを調べて呼び出すことができるように、フラットな遅延シーケンスIEnumerable<Node> ToEnumerable(Tree tree)
に変換します。treeaction


それでは、ある API を別の API に変換する方法を見てみましょう。

Visit上に提供するのは非常に簡単ですToEnumerable

void Visit(Tree tree, Action<Node> action) {
    ToEnumerable(tree).ForEach(action);
}

ただし、 (遅延シーケンスとして、リストは事前に作成されません)ToEnumerable上に提供できる言語の概念/機能はありますか?Visit

4

3 に答える 3

0

(ツリーのように) 各ノードにアクセスするコードを作成している場合、イテレーターで各ブランチのイテレーターを呼び出し、yield returnリーフ ノードで実行することができます。このアプローチは機能し、非常に単純ですが、非常に読みやすいが実行速度が非常に遅いコードになってしまうという重大な欠点があります。このサイトの他のいくつかの質問と回答は、反復子内でツリーを効率的にトラバースする方法についての洞察を提供します。

「ツリー」が単なる例であり、実際に持っているのが、各ノードでデリゲートを呼び出すルーチンを公開するクラスである場合 ( に似ていますList.ForEach())、 を公開しないIEnumerable場合、前者を使用して生成できる場合があります。 a List、これを繰り返すことができます。のようなものを使用するvar myList = new List<someThing>(); myCollection.ForEach( (x) => myList.Add(x) );と、列挙できる場合がありますmyList

リストに追加されたオブジェクトは、列挙が完了するまでに有効ではない可能性があるため、それでも不十分な場合は、必要なことを達成するために複数のスレッドを使用できる場合がまれにあります。たとえば、ForEachメソッドが各アイテムを使用できるように準備し、指定されたアクションを実行し、次に進む前に各アイテムをクリーンアップするメソッドを持つ 2 つの並べ替えられたコレクションがある場合、および 2 つの独立したコレクションからのアイテムに対するアクションをインターリーブする必要がある場合は、別々のスレッドでコレクションを繰り返し、同期プリミティブを使用して、各スレッドが必要に応じて他のスレッドを待機できるようにすることができます。

メソッドを介してのみ自身を公開するコレクションForEachは、そのような の実行中にアクセスを制限する傾向があることに注意してくださいForEach(そのような制限が必要でない場合、それらはおそらく を実装するでしょうIEnumerable)。前者が再開する前に後者が完了しなければならないため、ある人が呼び出した「項目アクション」が同じスレッドの同じコレクションでForEach別のアクションを実行する可能性があります。ただし、実行中に 2 番目のスレッドでを呼び出そうとすると、誤動作するか、最初の操作が完了するまで待機する可能性があります。最初のアクションが 2 番目のアクションを待っていた場合、デッドロックが発生します。このため、マルチスレッドが単に構築するよりもうまく機能するシナリオForEachForEachForEachForEachForEachListまれです。それにもかかわらず、それが役立つ場合がいくつかあります (たとえば、前述の独立したコレクションに対する「zipper」操作)。

于 2012-07-13T14:58:44.190 に答える
0

Not sure if I understand you correctly, but in Python, you can create iterable interface on any object. So you would just add special method __iter__ (which will yield nodes while traversing the tree). The visit procedure is then just about iterating through Tree object and calling action on each node.

于 2012-07-13T13:27:06.143 に答える
0

今はその考えが理解できたと思います。ここで必要な概念は、第 1 級継続、具体的にはcall/ccと呼ばれます。私にとって紛らわしいのは、C# が でこの概念の限定的な実装を既に提供しているyield returnことですが、それは私のシナリオには当てはまりません。

したがって、C# が完全な実装を提供する場合、ソリューションは次のようになります。

IEnumerable<Node> ToEnumerable(Tree tree) {
    tree.Visit(node => magic yield return node);
}

ラムダmagic yield returnからシーケンスを返す代わりに、 から次の要素を返します。node => ...ToEnumerable

yield returnただし、との正確な相関関係がわからないため、この回答はまだ完全ではありませんcall/cc。これを理解したら、回答を更新します。

于 2012-07-14T13:25:33.670 に答える