我需要将树型结构转换为2D数组。
我有一个人类:
public class Person
{
public string Name { get; set; }
public List<Person> Children { get; } = new List<Person>();
}
这样填充:
var parent = new Person {Name = "Parent"};
var child1 = new Person {Name = "Child 1"};
var grandchild1 = new Person {Name = "Grandchild 1"};
var child2 = new Person {Name = "Child 2"};
parent.Children.Add(child1);
child1.Children.Add(grandchild1);
parent.Children.Add(child2);
例如:
| Parent | | |
| | Child 1 | |
| | | Grandchild 1 |
| | Child 2 | |
我想将其转换为以下数组:
var expectedArray = new object[,]
{
{"Parent", null, null},
{null, "Child 1", null},
{null, null, "Grandchild 1"},
{null, "Child 2", null}
};
目前我已经写了几种扩展方法,但它确实非常混乱。这样做的正确方法是什么?优选地,采用简短的方法。
这是我到目前为止所尝试过的,但它确实非常混乱。
public static class PersonExtensions
{
public static object[,] To2DArray(this Person person)
{
var rowIndex = 0;
var columnIndex = 0;
var objectArray = new object[person.GetTotalPersonCount(), person.GetMaxDepth()];
var stack = new Stack<List<Person>.Enumerator>();
var enumerator = (new List<Person> {person}).GetEnumerator();
enumerator.MoveNext();
do
{
var currentPerson = enumerator.Current;
objectArray[rowIndex, columnIndex] = currentPerson.Name;
rowIndex++;
if (currentPerson.Children.Any())
{
// Depth is increasing
columnIndex++;
stack.Push(enumerator);
enumerator = currentPerson.Children.GetEnumerator();
}
// if (!enumerator.MoveNext() && stack.Count > 0)
while (!enumerator.MoveNext() && stack.Count > 0)
{
// Depth is decreasing
enumerator = stack.Pop();
columnIndex--;
}
}
while (stack.Count > 0);
return objectArray;
}
public static int GetMaxDepth(this Person entity)
{
int maxDepth = 0;
foreach (var childEntity in entity.Children)
{
maxDepth = Math.Max(maxDepth, childEntity.GetMaxDepth());
}
return maxDepth + 1;
}
public static int GetTotalPersonCount(this Person entity)
{
int count = 1;
foreach (var childEntity in entity.Children)
{
count += childEntity.GetTotalPersonCount();
}
return count;
}
}
修改 我已经设法通过用一段时间替换最终的if(深度减少)来使它工作。但它看起来仍然过于复杂。
答案 0 :(得分:0)
我相信这个问题可以通过两次使用深度优先搜索来解决。 首先,必须在第一遍中确定树的高度。需要知道深度,以便知道结果的每一行中有多少条目。
接下来,在第二遍中,必须生成实际条目,将节点的名称分配给与树中深度相对应的条目。
第一步可以通过使用Linq将其作为Person
类的扩展方法实现,如下所示。
public static int Depth(this Person iPerson)
{
if (iPerson.Children == null || iPerson.Children.Count() == 0)
{
return 1;
}
else
{
return 1 + Children.Max( iChild => iChild.Depth() );
}
}
第二步可以实现如下,其中iRoot
是树的根。
public static void DepthFirst(int Depth,
int CurrentDepth,
Person iRoot,
List<string>[] Result)
{
string[] NewEntry = new string[Depth];
NewEntry[CurrentDepth] = iPerson.Name;
Result.Add(NewEntry);
foreach(var iChild in iPerson.Children)
{
DepthFirst(Depth, CurrentDepth + 1, iChild, Result);
}
}
int Depth = iRoot.Depth();
var Result = new List<string[]>();
DepthFirst(Depth, 0, iRoot, Result).