How can I convert a text-file outline list into a recursive collection of objects?

c#, design-patterns, recursion, treeview

Solution

public class Item
{
    public string Name;
    public Item Parent;
}

List<Item> Collection = new List<Item>();

public void Main()
{
    var DataSource = data.InnerText;

    StreamReader Reader = new StreamReader(MapPath("_test2.txt"));
    int LastLevel = 0;

    while (Reader.EndOfStream == false) {
        var line = Reader.ReadLine();
        var Level = line.Where((System.Object c) => c == "-").Count;
        Item LastItem = default(Item);

        if (Collection.Count != 0) {
            LastItem = Collection.Last();
        }

        if (Level == 0) {
            Collection.Add(new Item { Name = line });
            LastLevel = 0;
        }
        else if (Level - LastLevel == 1) {
            Collection.Add(new Item { Name = line, Parent = LastItem });
            LastLevel += 1;
        }
        else if (Level == LastLevel) {
            Collection.Add(new Item { Name = line, Parent = LastItem.Parent });
        }
        else if (Level < LastLevel) {
            var LevelDiff = LastLevel - Level;
            Item Parent = LastItem;

            for (i = 0; i <= LevelDiff; i++) {
                Parent = Parent.Parent;
            }

            LastLevel = Level;
            Collection.Add(new Item { Name = line, Parent = Parent });
        }
    }

    Reader.Close();
}

This should do the trick. I tested it on your text file. There might be some bugs. Test it and tell if it works.

EDIT: Actually after further testing it turns out this does not work as expected. You need to add more logic to make it work. I leave that to you.

EDIT: After testing the code a bit more I have come to a version that works better. I still cannot guarantee that It will work under all circumstances.

Problem

How can I convert this text file content into a recursive collection of objects that I can bind to a TreeView? i.e. I want to end up with a collection of 3 objects, the first one called countries which has a collection of three child objects: france, germany, italy, and so on... ANSWER: thanks to all who helped out on this, here's my code that successfully parses this text outline into a XAML tree: http://tanguay.info/web/index.php?pg=codeExamples&id=358 ``` countries -france --paris --bordeaux -germany -italy subjects -math --algebra --calculus -science --chemistry --biology other -this -that ``` The code below is as far as I got it, but it is not dealing with multiple children of parents correctly. ``` using System; using System.Collections.Generic; using System.Text; namespace TestRecursive2342 { class Program { static void Main(string[] args) { List<OutlineObject> outlineObjects = new List<OutlineObject>(); //convert file contents to object collection List<string> lines = Helpers.GetFileAsLines(); Stack<OutlineObject> stack = new Stack<OutlineObject>(); foreach (var line in lines) { OutlineObject oo = new OutlineObject(line); if (stack.Count > 0) { OutlineObject topObject = stack.Peek(); if (topObject.Indent < oo.Indent) { topObject.OutlineObjects.Add(oo); stack.Push(oo); } else { stack.Pop(); stack.Push(oo); } } else { stack.Push(oo); } if(oo.Indent == 0) outlineObjects.Add(oo); } outlineObjects.ForEach(oo => Console.WriteLine(oo.Line)); Console.ReadLine(); } } public class OutlineObject { public List<OutlineObject> OutlineObjects { get; set; } public string Line { get; set; } public int Indent { get; set; } public OutlineObject(string rawLine) { OutlineObjects = new List<OutlineObject>(); Indent = rawLine.CountPrecedingDashes(); Line = rawLine.Trim(new char[] { '-', ' ', '\t' }); } } public static class Helpers { public static List<string> GetFileAsLines() { return new List<string> { "countries", "-france", "--paris", "--bordeaux", "-germany", "-italy", "subjects", "-math", "--algebra", "--calculus", "-science", "--chemistry", "--biology", "other", "-this", "-that"}; } public static int CountPrecedingDashes(this string line) { int tabs = 0; StringBuilder sb = new StringBuilder(); foreach (var c in line) { if (c == '-') tabs++; else break; } return tabs; } } } ```

Original source