sridharnetha
sridharnetha

Reputation: 2248

recursive function call in foreach throwing system.stackoverflowexception

I am getting a System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.' message.

My code as follows, Here I want to assign value to a variable recursively based on the condition and return the list.

public class FancyTree
{
    public string title { get; set; }
    public string key { get; set; }     
    public List<FancyTree> children { get; set; }
}

For example the FancyTree Class produces the output like parent->child or parent->parent->child or parent->parent->parent->child just like the Treeview structure.

public JsonResult EmployeesTree()
{  
   var output = converttoFancyTree(db.Database.GetEmployees(true));
   return Json(output, JsonRequestBehavior.AllowGet);
}
public List<FancyTree> converttoFancyTree(List<EmpTable> emps)
    {
        var output = new List<FancyTree>();
        foreach (var emp in emps)
        {
            var fancyTreeItem = new FancyTree();
            fancyTreeItem.key = emp.EMP_ID.ToString();
            fancyTreeItem.title = emp.EMP_NAME;

            if (!string.IsNullOrEmpty(emp.TEAM))
                {
                    //var empIDs = emp.TEAM?.Split(',')?.Select(Int32.Parse)?.ToList();
                    var tms = emp.TEAM.Split(',');
                    if (tms.Length > 0) {
                        var empIDs = new List<int>();
                        foreach (var t in tms) 
                        {
                            empIDs.Add(int.Parse(t));
                        }
                        var TeamMembers = emps.Where(x => empIDs.Contains(x.EMP_ID)).ToList();
                        if (TeamMembers.Count > 0)
                        {
                            var childrens = converttoFancyTree(TeamMembers);
                            fancyTreeItem.children = childrens;
                        }   
                    }                        
                }
            output.Add(fancyTreeItem);
        }
        return output;
    }

Upvotes: 0

Views: 201

Answers (1)

JonasH
JonasH

Reputation: 36541

I would assume your input is in the form of a plain list of objects, where each object contains the IDs of all the children, and you want to convert this to an object representation, i.e. something like:

public class Employee{
    public int Id {get;}
    public List<int> SubordinateIds {get;}
}

public class EmployeeTreeNode{
    public IReadOnlyList<EmployeeTreeNode> Subordinates {get;} ;
    public int Id {get;}
    public EmployeeTreeNode(int id, IEnumerable<EmployeeTreeNode> subordinates){
        Id = id;
        Subordinates = subordinates;
}

To convert this to a tree representation we can start by finding the roots of the tree, i.e. employees that are not subordinate to anyone.

var allSubordinates = allEmployees.SelectMany(e => e.SubordinateIds).ToList();
var allRoots = allEmployees.Select(e => e.Id).Except(allSubordinates);

We then need an efficient way to find a specific employee by the Id, i.e. a dictionary:

var employeeById = allEmployees.ToDictionary(e => e.Id, e => e.SubordinateIds);

We can then finally do the actual recursion, and we can create a generic helper method to assist:

public static TResult MapChildren<T, TResult>(
    T root, 
    Func<T, IEnumerable<T>> getChildren,
    Func<T,  IEnumerable<TResult>, TResult> map)
{
    return RecurseBody(root);
    TResult RecurseBody(T item) => map(item,  getChildren(item).Select(RecurseBody));
}
...

var tree = allRoots.Select(r => MapChildren(
    r, 
    id => employeeById[id], 
    (id, subordinates) => new EmployeeTreeNode(id, subordinates)));

This will recurse down to any employee without any subordinates, create EmployeeTreeNode for these, and then eventually traverse up the tree, creating node objects as it goes.

This assumes that there are no loops/cycles. If that is the case you do not have a tree, since trees are by definition acyclic, and the code will crash. You will instead need to handle the more general case of a graph, and this is a harder problem, and you will need to decide how the cycles should be handled.

Upvotes: 1

Related Questions