Solved

Modify method to recursive

Posted on 2010-11-12
13
366 Views
Last Modified: 2012-08-13
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,
0
Comment
Question by:dingir
  • 7
  • 5
13 Comments
 
LVL 18

Expert Comment

by:Richard Lee
ID: 34120007
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

0
 
LVL 18

Expert Comment

by:Richard Lee
ID: 34120047
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

0
 
LVL 1

Author Comment

by:dingir
ID: 34120105
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.



0
 
LVL 18

Expert Comment

by:Richard Lee
ID: 34120175
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
0
 
LVL 1

Author Comment

by:dingir
ID: 34120244
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.
0
 
LVL 18

Expert Comment

by:Richard Lee
ID: 34120689
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

0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 18

Expert Comment

by:Richard Lee
ID: 34120999
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

0
 
LVL 1

Author Comment

by:dingir
ID: 34121304
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)
0
 
LVL 18

Accepted Solution

by:
Richard Lee earned 250 total points
ID: 34121388
How about 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<SomeData> levels = new List<SomeData>();
	TreeView tw = new TreeView();

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

void Recursive(IEnumerable<SomeData> levels, string nodeHtml, TreeView tw, int depth, SomeData 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

0
 
LVL 18

Expert Comment

by:Richard Lee
ID: 34121455
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
0
 
LVL 33

Assisted Solution

by:Todd Gerbert
Todd Gerbert earned 250 total points
ID: 34121687
If am I to understand correctly, you want a data table of some sort listing the nodes for a TreeView and want a recursive function to add the nodes? And you don't already have a set format for the data table?

Assuming you have a table with three columns, "NodeID," "NodeText," and "ParentNode", with this dummy data:
NodeId,NodeText,ParentNode
1,Earth,0
2,Europe,1
3,North America,1
4,Asia,1
5,UK,2
6,France,2
7,Germany,2
8,Canada,3
9,USA,3
10,Mexico,3
11,China,4
12,India,4
13,Japan,4

Open in new window

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Data;



public partial class _Default : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

		DataTable treeViewItems = GetDummyTreeViewData();

		TreeNode root = new TreeNode();

		LoadTreeView(root, treeViewItems.AsEnumerable().Where(x => (int)x["ParentNode"] == 0).ToArray(), treeViewItems);

		TreeView1.Nodes.Add(root);

    }



	private void LoadTreeView(TreeNode node, DataRow[] items, DataTable itemsSource)

	{

		foreach (DataRow treeViewItem in items)

		{

			TreeNode newNode = new TreeNode((string)treeViewItem["NodeText"]);

			node.ChildNodes.Add(newNode);

			DataRow[] children = itemsSource.AsEnumerable().Where(x => (int)x["ParentNode"] == (int)treeViewItem["NodeId"]).ToArray();

			if (children.Length > 0)

				LoadTreeView(newNode, children, itemsSource);

		}

	}



	private DataTable GetDummyTreeViewData()

	{

		DataTable dt = new DataTable();

		dt.Columns.Add("NodeId", typeof(int));

		dt.Columns.Add("NodeText", typeof(string));

		dt.Columns.Add("ParentNode", typeof(int));



		dt.Rows.Add(1, "Earth", 0);

		dt.Rows.Add(2, "Europe", 1);

		dt.Rows.Add(3, "North America", 1);

		dt.Rows.Add(4, "Asia", 1);

		dt.Rows.Add(5, "UK", 2);

		dt.Rows.Add(6, "France", 2);

		dt.Rows.Add(7, "Germany", 2);

		dt.Rows.Add(8, "Canada", 3);

		dt.Rows.Add(9, "USA", 3);

		dt.Rows.Add(10, "Mexico", 3);

		dt.Rows.Add(11, "China", 4);

		dt.Rows.Add(12, "India", 4);

		dt.Rows.Add(13, "Japan", 4);



		return dt;

	}

}

Open in new window

0
 
LVL 1

Author Comment

by:dingir
ID: 34143894
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.
0
 
LVL 1

Author Closing Comment

by:dingir
ID: 34143907
This is EE when it's best,
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now