C# 将树结构转换为二维数组
我需要将树型结构转换为二维数组 我有个人课:C# 将树结构转换为二维数组,c#,arrays,tree,C#,Arrays,Tree,我需要将树型结构转换为二维数组 我有个人课: public class Person { public string Name { get; set; } public List<Person> Children { get; } = new List<Person>(); } 例如: 我想将其转换为以下数组: var expectedArray = new object[,] { {"Parent", null, null}, {nul
public class Person
{
public string Name { get; set; }
public List<Person> Children { get; } = new List<Person>();
}
例如:
我想将其转换为以下数组:
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;
}
}
公共静态类PersonExtensions
{
公共静态对象[,]到2darray(此人)
{
var-rowIndex=0;
风险价值指数=0;
var objectArray=新对象[person.GetTotalPersonCount(),person.GetMaxDepth()];
var stack=新堆栈();
var枚举器=(新列表{person}).GetEnumerator();
枚举数。MoveNext();
做
{
var currentPerson=枚举器.Current;
objectArray[rowIndex,columnIndex]=currentPerson.Name;
rowIndex++;
if(currentPerson.Children.Any())
{
//深度在增加
columnIndex++;
stack.Push(枚举器);
enumerator=currentPerson.Children.GetEnumerator();
}
//如果(!enumerator.MoveNext()&&stack.Count>0)
而(!enumerator.MoveNext()&&stack.Count>0)
{
//深度在减少
枚举数=stack.Pop();
列索引--;
}
}
而(stack.Count>0);
返回objectArray;
}
公共静态int GetMaxDepth(此人实体)
{
int maxDepth=0;
foreach(entity.childrenty中的var childEntity)
{
maxDepth=Math.Max(maxDepth,childEntity.GetMaxDepth());
}
返回最大深度+1;
}
公共静态int GetTotalPersonCount(此人实体)
{
整数计数=1;
foreach(entity.childrenty中的var childEntity)
{
count+=childEntity.GetTotalPersonCount();
}
返回计数;
}
}
编辑
我用一段时间替换了最终的if(深度下降),使其工作。不过,它看起来仍然过于复杂。我相信在两次过程中使用深度优先搜索可以解决这个问题。 首先,必须在第一次通过时确定树的高度。为了知道结果的每一行中有多少条记录,需要知道深度 接下来,在第二个过程中,必须生成实际条目,将节点的名称分配给与其在树中的深度相对应的条目
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).
第一步可以通过使用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).
publicstaticvoiddepthfirst(int-Depth,
int CurrentDepth,
伊洛特先生,
列表[]结果)
{
string[]NewEntry=新字符串[深度];
NewEntry[CurrentDepth]=iPerson.Name;
结果.添加(新条目);
foreach(iPerson.childs中的变量iChild)
{
深度优先(深度,CurrentDepth+1,iChild,结果);
}
}
int-Depth=iRoot.Depth();
var Result=新列表();
深度优先(深度、0、iRoot、结果)。
以下是它作为单个循环的工作方式(未经测试!):
如果你想让它看起来更干净一点,你可以这样做:
Func<bool> getNext = () =>
{
if (!enumerator.MoveNext())
{
if (stack.Count == 0) return false;
enumerator = stack.Pop(); columnIndex--;
}
return true;
};
while (getNext())
{
var currentPerson = enumerator.Current;
//etc.
}
Func getNext=()=>
{
如果(!enumerator.MoveNext())
{
if(stack.Count==0)返回false;
枚举数=stack.Pop();列索引--;
}
返回true;
};
while(getNext())
{
var currentPerson=枚举器.Current;
//等等。
}
已知树的最大深度吗?你只展示了3个,但是孙子孙女能生孩子吗?看起来你的解决方案是正确的-你看到了什么确切的错误?不,不幸的是,这还不知道。我不太明白为什么你觉得你需要tupleByEntity
字典-为什么你不能直接填充输出objectArray
的每个条目?无论如何,我看不出您的逻辑中有任何明显的错误。如果您为所有节点分配了一个ID号,那将非常简单。。你可以通过每个节点记录,无论它们在哪里添加myID、parentID、@Sefe谢天谢地都会相应地更新。我已经详细介绍了两种方法:GetMaxDepth和GetTotalPersonCount。我目前正在使用这些。
for (; ; )
if (!enumerator.MoveNext())
{
if (stack.Count == 0)
break; // finished
// Depth is decreasing
enumerator = stack.Pop();
columnIndex--;
}
else
{
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();
}
}
Func<bool> getNext = () =>
{
if (!enumerator.MoveNext())
{
if (stack.Count == 0) return false;
enumerator = stack.Pop(); columnIndex--;
}
return true;
};
while (getNext())
{
var currentPerson = enumerator.Current;
//etc.
}