Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将树结构转换为二维数组_C#_Arrays_Tree - Fatal编程技术网

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.
 }