【问题标题】:Easiest way to create a nested list from flat data从平面数据创建嵌套列表的最简单方法
【发布时间】:2009-12-28 22:23:08
【问题描述】:

假设我有以下平面格式的信息,例如对象列表:

List<Line> lines = new List<Line>
                                   {
                                       new Line{Id = 1, Level = 0},
                                       new Line{Id = 2, Level = 1},
                                       new Line{Id = 3, Level = 1},
                                       new Line{Id = 4, Level = 2},
                                       new Line{Id = 5, Level = 2},
                                       new Line{Id = 6, Level = 1},
                                       new Line{Id = 7, Level = 1},
                                       new Line{Id = 8, Level = 2},
                                       new Line{Id = 9, Level = 1}
                                   };

每个对象都有一个 id 和一个级别。我想以嵌套列表结束。为此,我有一个班级,可以根据级别列出孩子。

public class NestedLine
    {
        public int Id;
        public List<NestedLine> Children = new List<NestedLine>();
    }

将平面列表转换为嵌套列表的最简单方法是什么?

编辑:关于如何构建列表的唯一信息是行的顺序和级别。结果应该是这样的:

1
--2
--3
  --4
  --5
--6
--7
  --8
--9

【问题讨论】:

  • 我认为与所需输出的描述有些不一致。你能仔细检查一下吗?我不太明白如何从输入平面列表中推断出孩子属于哪个父母。
  • 我删除了描述并用图表替换了它。很抱歉造成混乱。

标签: c# algorithm


【解决方案1】:

这是我的尝试。

调用代码

List<Line> lines = new List<Line>
                           {
                               new Line{Id = 1, Level = 0},
                               new Line{Id = 2, Level = 1},
                               new Line{Id = 3, Level = 1},
                               new Line{Id = 4, Level = 2},
                               new Line{Id = 5, Level = 2},
                               new Line{Id = 6, Level = 1},
                               new Line{Id = 7, Level = 1},
                               new Line{Id = 8, Level = 2},
                               new Line{Id = 9, Level = 1}
                           };

NestedLine nestedLine = Recusrsive(lines, 0);

递归方法

private NestedLine Recusrsive(List<Line> lines, int listPos)
{
    NestedLine retVal = new NestedLine();
    Line line = lines[listPos];

    retVal.Id = line.Id;

    for (int iItem = listPos + 1; iItem < lines.Count; iItem++)
        if (lines[iItem].Level == line.Level + 1)
            retVal.Children.Add(Recusrsive(lines, iItem));
        else if (lines[iItem].Level <= line.Level) return retVal;

    return retVal;
}

【讨论】:

  • 我应该在int listPos中传递什么值
【解决方案2】:

您能在这里提供更多信息吗?这在我看来就像你真的在处理一个树结构:

1
-> 2
-> 3
-> -> 4
-> -> 5
-> 6
-> 7
-> -> 8
-> 9

我说的对吗?如果是,那么确定低级节点的父节点的规则是什么?

首先想到的是为您的 NestedLine 类使用递归构造函数:

public NestedLine(列表行)

【讨论】:

  • 是的,就是这样。规则很简单,就是列表的顺序加上层级。
  • 天哪! SO编辑今天早上杀了我!基本上,我将从 NestedLine 的递归构造函数开始。假设集合的第一个元素是正在构造的节点,然后剪掉第一个节点,查看集合的其余部分,并将其传递给新的 NestedLine 对象,然后将这些对象添加到当前的 NestedLine 对象中。我会写一个小代码示例,稍后再推。
  • astander 的回答,上面看起来就像我想要得到的。我会把它移到 NestedLine 的构造函数中,但静态方法也可以工作 - 我会给他投票。
【解决方案3】:

使用堆栈来跟踪在每个级别添加的最后一个项目是什么,随着您的进行推送和弹出:

var stack = new Stack<NestedLine>();
foreach (var line : lines) {
    while (stack.Count > line.Level) {
        // Pop items until the top element is one up from current level
        stack.Pop()
    }
    var child = new NestedLine{Id = line.Id};
    if (stack.Count > 0) {
        // if there is a parent, add the child to its children
        stack.Peek().Children.Add(child);
    }
    // add current line as the deepest item
    stack.Push(child);
}
NestedLine root;
while (stack.Count) {
    root = stack.Pop();
}

免责声明:我实际上没有做过很多 C# 编程,所以这可能包含一些微不足道的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-27
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多