0

I have this model:

public class TreeModel
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Name { get; set; }

    public static List<TreeModel> GetData()
    {
        var list = new List<TreeModel>()
        {
            new TreeModel() {Id = 1,ParentId = null,Name = "Name1"},
              new TreeModel() {Id = 2,ParentId = null,Name = "Name2"},
                new TreeModel() {Id = 3,ParentId = null,Name = "Name3"},
                  new TreeModel() {Id = 4,ParentId = 1,Name = "Name4"},
                    new TreeModel() {Id = 5,ParentId = 1,Name = "Name5"},
                      new TreeModel() {Id = 6,ParentId = 4,Name = "Name6"},
                        new TreeModel() {Id = 7,ParentId = 6,Name = "Name7"},
        };

        return list;
    }

    public static string ShowTree(List<TreeModel> source)
    {
        var text = "";
        foreach (var item in source)
        {
            if (item.ParentId != null) continue;
            text += item.Name + "\n";
            var childs = source.Where(x => x.ParentId == item.Id).ToList();
            if (!childs.Any()) continue;
            {
                foreach (var child in childs)
                {
                    text += "  " + child.Name + "\n"; //2 spaces
                    var childs2 = source.Where(x => x.ParentId == child.Id).ToList();
                    if (!childs2.Any()) continue;
                    {
                        foreach (var child2 in childs2)
                        {
                            text += "    " + child2.Name + "\n"; //4 spaces
                            var childs3 = source.Where(x => x.ParentId == child2.Id).ToList();
                            if (!childs3.Any()) continue;
                            foreach (var child3 in childs3)
                            {
                                text += "      " + child3.Name + "\n"; //6 spaces
                            }
                        }
                    }
                }
            }
        }
        return text;
    }

}

with my method ShowTree, I am able to get this:

Name1
  Name4
    Name6
      Name7
  Name5
Name2
Name3

Can someone help me transform this method in recursive one, in order to use it with a larger data-set.

Lucian Bumb
  • 2,821
  • 5
  • 26
  • 39
  • See following posting : http://stackoverflow.com/questions/28976601/recursion-parsing-xml-file-with-attributes-into-treeview-c-sharp – jdweng Aug 22 '16 at 20:54
  • @jdweng my situation is opposite to that question, I have a Tree, and I need to use his data to create a multi-line string in a tree structure. I need this string to use it on a Devexpress XtraReport. – Lucian Bumb Aug 22 '16 at 21:01

3 Answers3

2

You need to use a recursive function :

public static string ShowTree(List<TreeModel> source)
{
    var buffer = new StringBuilder();
    foreach (var item in source.Where(x => !x.ParentId.HasValue))
    {
        WriteTree(buffer, source, item);
    }

    return buffer.ToString();
}
private static void WriteTree(StringBuilder buffer, List<TreeModel> source, TreeModel item, int level = 0)
{
    buffer.AppendLine(new string('\t', level) + item.Name);
    foreach (var child in source.Where(x => x.ParentId == item.Id))
    {
        WriteTree(buffer, source, child, level + 1);
    }
}
Xiaoy312
  • 14,292
  • 1
  • 32
  • 44
1

Just call the ShowTree method and you will get your formatted data.

Edit: Using StringBuilder because of better performance:

public static string ShowTree(List<TreeModel> source) {
    var empty = new StringBuilder();
    source.Where(s => s.ParentId == null).ToList().ForEach(s => ShowNode(source, s, empty));
    return empty.ToString();
}

private static void ShowNode(List<TreeModel> source, TreeModel model, StringBuilder text, int depth = 0) {
    text.Append(Enumerable.Repeat(" ", depth++).Aggregate("", (s, s1) => s + s1) + model.Name + "\n");

    source.ForEach(m => {
        if (model.Id == m.ParentId) ShowNode(source, m, text, depth);
    });
}
whymatter
  • 755
  • 8
  • 18
  • 1
    That is one awkward way to pass a string reference around... May I introduce your to [`ref`](http://stackoverflow.com/documentation/c%23/26/keywords/184/ref-out). – Xiaoy312 Aug 22 '16 at 21:16
  • I can't use ref because of the anonnymous function inside ForEach. I'm using StringBuilder now, which is also good for performance. – whymatter Aug 22 '16 at 21:17
  • You could've just used an standard `foreach`-loop – Xiaoy312 Aug 22 '16 at 21:18
  • thank you, your solution is working, and I accepted the answer because you used spaces. – Lucian Bumb Aug 22 '16 at 21:23
1

Try following code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace ProgrammingBasics
{
    class Program
    {
        static void Main(string[] args)
        {
            TreeModel model = new TreeModel();
            string text = model.ShowTree();
            Console.WriteLine(text);
            Console.ReadLine();
        }
    }
    public class TreeModel
    {
        public int Id { get; set; }
        public int? ParentId { get; set; }
        public string Name { get; set; }

        public static List<TreeModel> GetData()
        {
            var list = new List<TreeModel>()
            {
                new TreeModel() {Id = 1,ParentId = null,Name = "Name1"},
                new TreeModel() {Id = 2,ParentId = null,Name = "Name2"},
                new TreeModel() {Id = 3,ParentId = null,Name = "Name3"},
                new TreeModel() {Id = 4,ParentId = 1,Name = "Name4"},
                new TreeModel() {Id = 5,ParentId = 1,Name = "Name5"},
                new TreeModel() {Id = 6,ParentId = 4,Name = "Name6"},
                new TreeModel() {Id = 7,ParentId = 6,Name = "Name7"},
            };

            return list;
        }
        public string ShowTree()
        {
            int level = 0;
            return ShowTreeRecursive(GetData(), level, null); 
        }

        public static string ShowTreeRecursive(List<TreeModel> source, int level, int? ParentId)
        {
            string text = "";
            foreach(var node in source.Where(x => x.ParentId == ParentId))
            {
                text += string.Format("{0} {1}\n", new string(' ', 3 * level), node.Name);
                text += ShowTreeRecursive(source, level + 1, node.Id);
            }
            return text;
        }
    }

}
jdweng
  • 33,250
  • 2
  • 15
  • 20