次のような文字列があります。
/Test Town
/Test Town/Interior
/Test Dungeon/Secret
パスの任意のリストが与えられた場合、葉ノードを自動的に生成するにはどうすればよいですか? 解決策には再帰が含まれると思いますが、うまくいきません。
ループを使用してやろうとしましたが、最初のレベルしか取得できませんでした。
上記は次のようなものを生成します:
これはかなりうまく機能します。
まず、ツリー構造を作成する必要がありました。
public class Tree<T> : List<Tree<T>>
{
public Tree(T value, IEnumerable<Tree<T>> children)
{
this.Value = value;
this.AddRange(children);
}
public T Value { get; set; }
}
ここで、ツリーを構築するための再帰関数が必要になりました。
Func<
IEnumerable<IEnumerable<string>>,
IEnumerable<Tree<string>>>
buildTree = null;
buildTree = xss =>
xss
.ToLookup(xs => xs.FirstOrDefault(), xs => xs.Skip(1))
.Where(xs => xs.Key != null)
.Select(xs => new Tree<string>(xs.Key, buildTree(xs)));
次に、lines
変数に文字列のリストがあるので、実行する必要がありました。
var tree =
buildTree(lines
.Select(x => new [] { "Root", }.Concat(x.Split('/').Skip(1))));
以上です。Tree<T>
クラスを数えなければ、これはわずか 3 行のコードです。単純。
別の方法として、匿名メソッドを使用したくない場合は、ツリー クラスを次のように変更できます。
public class Tree<T> : List<Tree<T>>
{
public Tree(T value, IEnumerable<IEnumerable<T>> inner)
{
this.Value = value;
this.AddRange(inner
.ToLookup(xs => xs.FirstOrDefault(), xs => xs.Skip(1))
.Where(xs => xs.Key != null)
.Select(xs => new Tree<T>(xs.Key, xs)));
}
public T Value { get; set; }
}
これは次のように呼び出されます。
var tree = new Tree<string>("Root", lines.Select(x => x.Split('/').Skip(1)));
Tree<T>
ただし、これは、クラスを制御する必要があることを意味します。
最初の解決策は、任意のツリー構造を使用できることを意味します。
で動作するバージョンは次のSystem.Windows.Forms.TreeNode
とおりです。
Func<
IEnumerable<IEnumerable<string>>,
IEnumerable<TreeNode>>
buildTreeNode = null;
buildTreeNode = xss =>
xss
.ToLookup(xs => xs.FirstOrDefault(), xs => xs.Skip(1))
.Where(xs => xs.Key != null)
.Select(xs => new TreeNode(xs.Key, buildTreeNode(xs).ToArray()));