Solved

Modify method to recursive

Posted on 2010-11-12
13
372 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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
 
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

SharePoint Admin?

Enable Your Employees To Focus On The Core With Intuitive Onscreen Guidance That is With You At The Moment of Need.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
This article introduced a TextBox that supports transparent background.   Introduction TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the…
This is a high-level webinar that covers the history of enterprise open source database use. It addresses both the advantages companies see in using open source database technologies, as well as the fears and reservations they might have. In this…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…

691 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