我有一些字符串看起来:
/Test Town
/Test Town/Interior
/Test Dungeon/Secret
给定一个任意的pathes列表,如何自动生成叶子节点?我想解决方案涉及递归,但我无法得到它。
我尝试使用循环但是我只获得了第一级。
上面会产生类似的东西:
答案 0 :(得分:4)
这很有效。
首先,我必须创建一个树结构:
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>
类,那么这只是三行代码。简单。
另外,如果您不想使用匿名方法,可以像这样修改树类:
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()));