从列表构建缩进结构的想法?

时间:2012-06-23 19:00:18

标签: c# .net list recursion

我有一个List(.NET),需要构建一个缩进的树结构。列表中的每个项目都有一个Position属性,指示缩进级别。最终结构应如下所示:

// (1) 1
//      (2) 1-1
//      (2) 1-2
//      (2) 1-3
// (1) 2
//      (2) 2-1
//          (3) 2-1-1
// (1) 3

括号内的数字是Position属性。给定级别的每个后续项目都应该有一个标签,表明该级别的项目列表中的计数。较低的位置级别将具有一种轮廓格式标签,如示例中所示。请记住,我必须正确生成这些标签。

老实说,我已经做了一段时间的递归工作,尽管我认为这将是最好的解决方案,但我只是坚持如何完成工作。我可能过于复杂了。我的想法是,当我到达一片叶子时,"我应该从列表中删除该项目并返回,但我不确定。只是旋转我的车轮。

谢谢, 杰

更新

这里有些接近,但我在查明最后一个案例时遇到了麻烦。到目前为止,如果下一个项目落在同一级别或缩进一个级别,它会很好,但我需要一个案例,当列表中的下一个项目位于小于当前项目的位置时(即,缩进到更远的位置)左边)。另外,我不确定该方法顶部的基本情况:

var sb = new StringBuilder();
BuildTree(sb, list, 0, 1, string.Empty);
return sb.ToString();

private void BuildTree(StringBuilder sb, List<Item> list, int currIndex, int count, string parentId)
{
    if (list.Count == currIndex)
    {
        return;
    }

    // Build my item.
    string currId = parentId == string.Empty ? count.ToString() : parentId + "-" + count;
    sb.Append(currId + "<br />");

    if (list[currIndex + 1].Position == list[currIndex].Position)
    {
        BuildTree(sb, list, currIndex + 1, count + 1, parentId);
    }

    if (list[currIndex + 1].Position > list[currIndex].Position)
    {
        BuildTree(sb, list, currIndex + 1, 1, currId);
    }
}

更新

另一种实现,但对于较少缩进行的情况仍然失败:

private void BuildTree(StringBuilder sb, List<Item> list, int currIndex, int count, string parentId)
{
    if (list.Count == 0)
    {
        return;
    }

    // Build my item.
    string currId = parentId == string.Empty ? count.ToString() : parentId + "-" + count;
    sb.Append(currId + "<br />");

    if (list[currIndex + 1].Position == list[currIndex].Position)
    {
        BuildTree(sb, list, currIndex + 1, count + 1, parentId);
    }

    if (list[currIndex + 1].Position > list[currIndex].Position)
    {
        BuildTree(sb, list, currIndex + 1, 1, currId);
    }

    list.RemoveAt(currIndex);
}

更新

这是一个黑客攻击,但它确实有效。我基本上是在根下构建多个子树。我更喜欢一个合适的解决方案,而不是一个黑客,但这是我迄今为止最好的尝试。欢迎替代方案:

var sb = new StringBuilder();
List<Person> list = GetTheList();
int cnt = 0;
while (list.Count > 0)
{
    BuildTree(sb, list, 0, ++cnt, string.Empty);
}

return sb.ToString();


private void BuildTree(StringBuilder sb, List<Person> list, int currIndex, int count, string parentId)
{
    // Build my item.
    string currId = parentId == string.Empty ? count.ToString() : parentId + "-" + count;
    sb.Append(currId + "<br />");

    if (list.Count > 1)
    {
        if (list[currIndex + 1].Position == list[currIndex].Position)
        {
            BuildTree(sb, list, currIndex + 1, count + 1, parentId);
        }

        if (list[currIndex + 1].Position > list[currIndex].Position)
        {
            BuildTree(sb, list, currIndex + 1, 1, currId);
        }
    }

    list.RemoveAt(currIndex);
}

2 个答案:

答案 0 :(得分:0)

这是一个选项。它没什么特别的,也许甚至不是很漂亮,并且肯定没有任何健全性检查或错误处理逻辑,但它支持你所说明的结构。

输出应该与您在问题顶部的输出类似,并且它有望引导您朝着正确的方向前进。

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    public class Program
    {
        private static readonly IndentedList indentedList = new IndentedList();

        static void Main()
        {
            Fill();
            indentedList.Items.ForEach(Print);
        }

        private static void Fill()
        {
            indentedList.Add(new Node()); // 1
            indentedList.Add(new Node()); // 2
            indentedList.Add(new Node()); // 3

            indentedList.Items[0].Add(new Node()); // 1-1
            indentedList.Items[0].Add(new Node()); // 1-2
            indentedList.Items[0].Add(new Node()); // 1-3

            indentedList.Items[1].Add(new Node()); // 2-1
            indentedList.Items[1].Children[0].Add(new Node()); // 2-1-1
        }

        private static void Print(Node node)
        {
            var indentation = new String('\t', node.IndentationLevel - 1);
            Console.WriteLine("{0}({1}) {2}", indentation, node.IndentationLevel, node);
            node.Children.ForEach(Print);
        }
    }

    public class IndentedList
    {
        private readonly Node superNode = new Node();

        public List<Node> Items { get { return superNode.Children; } }

        public void Add(Node node)
        {
            superNode.Add(node);
        }
    }

    public class Node
    {
        public int IndentationLevel { get { return parent == null ? 0 : parent.IndentationLevel + 1; } }
        public int Position { get { return parent.Children.IndexOf(this) + 1; } }
        public List<Node> Children { get; private set; }

        private Node parent;
        private bool IsRootNode { get { return parent.parent == null; } }

        public Node()
        {
            Children = new List<Node>();
        }

        public void Add(Node child)
        {
            child.parent = this;
            Children.Add(child);
        }

        public override string ToString()
        {
            return IsRootNode ? Position.ToString() : String.Format("{0}-{1}", parent, Position);
        }
    }
}

答案 1 :(得分:0)

var sb = new StringBuilder();
List<Person> list = GetTheList();
int cnt = 0;
// The loop is necessary to iterate over the root elements.
while (list.Count > 0)
{
    BuildTree(sb, list, 0, ++cnt, string.Empty);
}

return sb.ToString();


private void BuildTree(StringBuilder sb, List<Person> list, int currIndex, int count, string parentId)
{
    string currId = parentId == string.Empty ? count.ToString() : parentId + "-" + count;
    sb.Append(currId + "<br />");

    if (list.Count > 1)
    {
        if (list[currIndex + 1].Position == list[currIndex].Position)
        {
            BuildTree(sb, list, currIndex + 1, count + 1, parentId);
        }

        if (list[currIndex + 1].Position > list[currIndex].Position)
        {
            BuildTree(sb, list, currIndex + 1, 1, currId);
        }
    }

    list.RemoveAt(currIndex);
}