Solved

Modify method to recursive

Posted on 2010-11-12
13
371 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
Salesforce Made Easy to Use

On-screen guidance at the moment of need enables you & your employees to focus on the core, you can now boost your adoption rates swiftly and simply with one easy tool.

 
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

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!

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…
Summary: Persistence is the capability of an application to store the state of objects and recover it when necessary. This article compares the two common types of serialization in aspects of data access, readability, and runtime cost. A ready-to…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

730 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