Link to home
Start Free TrialLog in
Avatar of dingir
dingirFlag for Sweden

asked on

Modify method to recursive

I would like some help with modifying this to a recursive function.

        string nodeHtml = "<div class='fll'> <div class='tw1'>{0}</div><div class='tw2'>{1}</div> </div>";

        TreeNode l1Node = null;
        TreeNode l2Node = null;
        TreeNode l3Node = null;

        foreach (SomeList sub1 in levels.Where(d => d.Level == 1))
        {
            l1Node = new TreeNode(string.Format(nodeHtml, sub1.Username, sub1.UserId.ToString(), "", sub1.UserId));
            foreach (SomeList sub2 in levels.Where(d => d.subUserId == sub1.UserId))
            {
                l2Node = new TreeNode(string.Format(nodeHtml, sub2.Username, sub2.UserId.ToString(), "", sub2.UserId));
                foreach (SomeList sub3 in levels.Where(d => d.subUserId == sub2.UserId))
                {
                    l3Node = new TreeNode(string.Format(nodeHtml, sub3.Username, sub3.UserId.ToString(), "", sub3.UserId));
                    foreach (SomeList sub4 in levels.Where(d => d.subUserId == sub3.UserId))
                    {
                        TreeNode n4 = new TreeNode(string.Format(nodeHtml, sub4.Username, sub4.UserId.ToString(), "", sub4.UserId));
                        l3Node.ChildNodes.Add(n4);
                    }
                    tw.Nodes.Add(l3Node);
                    l2Node.ChildNodes.Add(l3Node);
                }
                tw.Nodes.Add(l2Node);
                l1Node.ChildNodes.Add(l2Node);
            }
            tw.Nodes.Add(l1Node);
            tw.CollapseAll();
        }



Also other ideas of optimations are welcome,
Avatar of Avodah
Avodah
Flag of United Kingdom of Great Britain and Northern Ireland image

The nature of your functionality does not lend itself ideally to recursion because your conditional clauses vary. Saying this I have written something that does the trick.

DaTribe
public class SomeList
{
	public int Level { get; set; }
	public int subUserId { get; set; }
	public string Username { get; set; }
	public int UserId { get; set; }
}

protected void Page_Load(object sender, EventArgs e)
{
	string nodeHtml = "<div class='fll'> <div class='tw1'>{0}</div><div class='tw2'>{1}</div> </div>";
	List<SomeList> levels = new List<SomeList>();
	TreeView tw = new TreeView();

	Recursive(levels, nodeHtml, tw, 0, null, null);
}

void Recursive(IEnumerable<SomeList> levels, string nodeHtml, TreeView tw, int depth, SomeList item, TreeNode parentNode)
{
	switch(depth)
	{
		case 0:
			levels
				.Where(d => d.Level == 1)
				.ToList()
				.ForEach(sub =>
				         	{
				         		var node = new TreeNode(string.Format(nodeHtml, sub.Username, sub.UserId.ToString(), String.Empty, sub.UserId));
				         		Recursive(levels, nodeHtml, tw, ++depth, sub, node);
								tw.Nodes.Add(node);
				         		tw.CollapseAll();
				         	});
		    break;
		case 1:
		case 2:
		case 3:
			levels
				.Where(d => d.subUserId == item.UserId)
				.ToList()
				.ForEach(sub =>
				         	{
								var node = new TreeNode(string.Format(nodeHtml, item.Username, item.UserId.ToString(), String.Empty, sub.UserId));

								if(depth < 3)
									tw.Nodes.Add(node);

								parentNode.ChildNodes.Add(node);
				         	});
		    break;
	}
}

Open in new window

I forgot the last recursive call. Here is the sample again.

DaTribe
void Recursive(IEnumerable<SomeList> levels, string nodeHtml, TreeView tw, int depth, SomeList item, TreeNode parentNode)
{
	switch(depth)
	{
		case 0:
			levels
				.Where(d => d.Level == 1)
				.ToList()
				.ForEach(sub =>
				         	{
				         		var node = new TreeNode(string.Format(nodeHtml, sub.Username, sub.UserId.ToString(), String.Empty, sub.UserId));
				         		Recursive(levels, nodeHtml, tw, ++depth, sub, node);
								tw.Nodes.Add(node);
				         		tw.CollapseAll();
				         	});
		    break;
		case 1:
		case 2:
		case 3:
			levels
				.Where(d => d.subUserId == item.UserId)
				.ToList()
				.ForEach(sub =>
				         	{
								var node = new TreeNode(string.Format(nodeHtml, item.Username, item.UserId.ToString(), String.Empty, sub.UserId));

								if (depth < 3)
								{
									Recursive(levels, nodeHtml, tw, ++depth, sub, node);
									tw.Nodes.Add(node);
								}

				         		parentNode.ChildNodes.Add(node);
				         	});
		    break;
	}
}

Open in new window

Avatar of dingir

ASKER

First: Thank's,

The thing is. There are a problem from start in this code.
There are really no variation in the clauses.

The child nodes are from the same data source, i did never got it correct in one dataset.

id subid
 -- getAllWhere(subid == id)
 -- -- getAllWhere(subid == id)
 -- -- -- getAllWhere(subid == id)
 -- -- -- -- getAllWhere(subid == id)

... and so on.. infinite.

..would be the optimal.



I will have another go however your first where clause is different.

levels.Where(d => d.Level == 1)
levels.Where(d => d.subUserId == sub1.UserId)
levels.Where(d => d.subUserId == sub2.UserId)
levels.Where(d => d.subUserId == sub3.UserId)

plus on your most inner iteration you have chosen not to add the nodes to the root of the treeview therefore forcing the logic to determine when it is at the bottom (logic varies)

DaTribe
Avatar of dingir

ASKER

Thanks

The Level isn't a part of the data.
"Level" is generated and attached to the dataset on collection of data, to sort out the different levels of deep.

id subid
 -- id, subid
 -- -- id, subid
 -- -- -- id, subid
 -- -- -- -- id, subid
and so on..


This is the plain design of the table. you know, like a table-id-field with a relation to another field within the table itself.
Sorry for the delay, had to grab something to eat.

Try this:

DaTribe
protected void Page_Load(object sender, EventArgs e)
{
	string nodeHtml = "<div class='fll'> <div class='tw1'>{0}</div><div class='tw2'>{1}</div> </div>";
	List<SomeList> levels = new List<SomeList>();
	TreeView tw = new TreeView();

	levels
		.Where(d => d.Level == 1)
		.ToList()
		.ForEach(sub =>
     	{
     		var node =
     			new TreeNode(string.Format(nodeHtml, sub.Username, sub.UserId.ToString(), String.Empty, sub.UserId));
     		Recursive(levels, nodeHtml, tw, 0, sub, node);
     		tw.Nodes.Add(node);
     		tw.CollapseAll();
     	});
}

void Recursive(IEnumerable<SomeList> levels, string nodeHtml, TreeView tw, int depth, SomeList item, TreeNode parentNode)
{
	levels
		.Where(d => d.subUserId == item.UserId)
		.ToList()
		.ForEach(sub =>
		{
			var node = new TreeNode(string.Format(nodeHtml, item.Username, item.UserId.ToString(), String.Empty, sub.UserId));
			Recursive(levels, nodeHtml, tw, ++depth, sub, node);
			tw.Nodes.Add(node);

			if(depth < levels.Count())
				parentNode.ChildNodes.Add(node);
		});
}

Open in new window

A slight variation on the solution plus putting the CollapseAll outside the loop.

DaTribe
protected void Page_Load(object sender, EventArgs e)
{
	string nodeHtml = "<div class='fll'> <div class='tw1'>{0}</div><div class='tw2'>{1}</div> </div>";
	List<SomeList> levels = new List<SomeList>();
	TreeView tw = new TreeView();

	foreach (SomeList sub in levels.Where(d => d.Level == 1))
	{
		var node = new TreeNode(string.Format(nodeHtml, sub.Username, sub.UserId, String.Empty, sub.UserId));
		Recursive(levels, nodeHtml, tw, 0, sub, node);
		tw.Nodes.Add(node);
	}
	tw.CollapseAll();
}

void Recursive(IEnumerable<SomeList> levels, string nodeHtml, TreeView tw, int depth, SomeList item, TreeNode parentNode)
{
	levels
		.Where(d => d.subUserId == item.UserId)
		.ToList()
		.ForEach(sub =>
		{
			var node = new TreeNode(string.Format(nodeHtml, item.Username, item.UserId.ToString(), String.Empty, sub.UserId));
			Recursive(levels, nodeHtml, tw, ++depth, sub, node);
			tw.Nodes.Add(node);

			if(depth < levels.Count())
				parentNode.ChildNodes.Add(node);
		});
}

Open in new window

Avatar of dingir

ASKER

Thanks
though, try to skip the level-part.. :)

Level 1,2,3,4 are fictive, added data! I want the treeview to understand itself that there are no more nodes in

id,subid
and automatically understand to check next level of id,subid and add another node/items for that.

I can't think how to explain it better.. (except that I understand u still refer answers regarding to my original post)
ASKER CERTIFIED SOLUTION
Avatar of Avodah
Avodah
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
The more I look at this (it could just be that it is late in the day) is that the trigger that ends the recursive loop is incorrect and there is no accurate way to determine how  to end.

// This seems to be incorrect
if(depth < levels.Count())

The simple question is, how do you determine you are at the maximum depth?

DaTribe
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of dingir

ASKER

tgerbert,

You stroked exactly into my point! Thank's a lot for that superplain and clean sample.

But because this was a side question, i split the points to you and daTribe.

Also I understand a little more that the treeview / recursive nodes way to think, isn't rocket science but still also not the simpliest of logic to achieve.
Avatar of dingir

ASKER

This is EE when it's best,