Association of Tenodes

Does anyone know of an algorithm that integrates treenodes as follows?

treeA \ child a \node(abc) \ child b \node(xyz) + treeB \ child a \node(qrs) \ child b \node(xyz) \node(pdq) \ child c \node(pdq) = // do merge treeMerged \ child a \node(abc) \node(qrs) \ child b \node(xyz) \node(pdq) \ child c \node(pdq) 

Any help would be greatly appreciated.

+4
source share
4 answers

Well, as soon as I really took the time to think about it, the solution turned out to be much simpler than I expected. (I wrote a critical piece of code below)

  private TreeNode DoMerge(TreeNode source, TreeNode target) { if (source == null || target == null) return null; foreach (TreeNode n in source.Nodes) { // see if there is a match in target var match = FindNode(n, target.Nodes); // match paths if (match == null) { // no match was found so add n to the target target.Nodes.Add(n); } else { // a match was found so add the children of match DoMerge(n, match); } } return target; } 

Still wondering if anyone has a better solution?

+4
source

Well, I admit that when I first started talking with this, I did not think it would be too complicated, so I decided that I would try to do it with LINQ. It turned out to be a nut, but it works. I'm sure there are more elegant and efficient algorithms, but here it is!

Firstly, I have a ToEnumerable extension method in the TreeNodeCollection class:

  public static class TreeNodeCollectionExtensions { public static IEnumerable<TreeNode> ToEnumerable(this TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { yield return node; } } } 

Then I implement a custom mapper:

public class TreeNodeComparer: IEqualityComparer {

 public bool Equals(TreeNode x, TreeNode y) { return x.Text == y.Text; } public int GetHashCode(TreeNode obj) { return obj.Text.GetHashCode(); } 

}

And finally, madness:

 private TreeView MergeTreeViews(TreeView tv1, TreeView tv2) { var result = new TreeView(); foreach (TreeNode node in tv2.Nodes) { result.Nodes.Add(node.Clone() as TreeNode); } foreach (TreeNode node in tv1.Nodes) { var nodeOnOtherSide = result.Nodes.ToEnumerable() .SingleOrDefault(tr => tr.Text == node.Text); if (nodeOnOtherSide == null) { TreeNode clone = node.Clone() as TreeNode; result.Nodes.Add(clone); } else { var n = node.Nodes.ToEnumerable() .Where(t => !(nodeOnOtherSide.Nodes.ToEnumerable() .Contains(t, new TreeNodeComparer()))); foreach (TreeNode subNode in n) { TreeNode clone = subNode.Clone() as TreeNode; nodeOnOtherSide.Nodes.Add(clone); } } } return result; } 

The way I encoded this was that it returns a third "merged" treeView. You can change the code so that it takes the third tree view as a parameter, so you can go to the treeView, which you may already have.

Again, I'm sure there is a better way to do this, but it SHOULD work.

Another thing that I would like to point out is that it will only work for TreeView, which has two layers.

+2
source

I came up with this recursive example, it works fine in C # (I used it myself), note that you need to find a way to convert TreeNode.Nodes to an array:

 public static TreeNode[] mergeTrees(TreeNode[] target, TreeNode[] source) { if (source == null || source.Length == 0) { return target; } if (target == null || target.Length == 0) { return source; } bool found; foreach (TreeNode s in source) { found = false; foreach (TreeNode t in target) { if (s.Text.CompareTo(t.Text) == 0) { found = true; TreeNode[] updatedNodes = mergeTrees(Util.treeView2Array(t.Nodes), Util.treeView2Array(s.Nodes)); t.Nodes.Clear(); t.Nodes.AddRange(updatedNodes); break; } } if (!found) { TreeNode[] newNodes = new TreeNode[target.Length + 1]; Array.Copy(target, newNodes, target.Length); newNodes[target.Length] = s; target = newNodes; } } return target; } 
+2
source

If you use the Node.Name attribute to set the actual path of the element, then merging is somewhat simple.

First, create a TreeNodeCollection extension similar to this (this is necessary to use the Case Sensitive Find () method for TreeNodeCollection, which ensures that a unique path can be unique to Case as well):

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace TreeViewApp { public static class TreeNodeCollectionExtensions { public static TreeNode[] FindExact(this TreeNodeCollection coll, string keytofind) { TreeNode[] retval; if (String.IsNullOrWhiteSpace(keytofind) || coll == null) { retval = new TreeNode[0]; } else { TreeNode[] badfinds = coll.Find(keytofind, true); List<TreeNode> goodfinds = new List<TreeNode>(); foreach (TreeNode bad in badfinds) { if (bad.Name == keytofind) goodfinds.Add(bad); } retval = goodfinds.ToArray(); } return retval; } } } 

Secondly, fill the tree structure with your source nodes ...
Thrid, fill the tree structure with target nodes ...
Fourth, create an empty tree.

and then, it's that simple:

  private void btn_Merge_Click(object sender, EventArgs e) { //first merge foreach (TreeNode sourceNode in this.treeview_Source.Nodes) { FindOrAdd(sourceNode, ref this.treeview_Merged); } //second merge foreach (TreeNode targetNode in this.treeview_Target.Nodes) { FindOrAdd(targetNode, ref this.treeview_Merged); } } private void FindOrAdd(TreeNode FindMe, ref TreeView InHere) { TreeNode[] found = InHere.Nodes.FindExact(FindMe.Name); //if the node is not found, add it at the proper location. if (found.Length == 0) { if (FindMe.Parent != null) { TreeNode[] foundParent = InHere.Nodes.FindExact(FindMe.Parent.Name); if (foundParent.Length == 0) InHere.Nodes.Add((TreeNode)FindMe.Clone()); else foundParent[0].Nodes.Add((TreeNode)FindMe.Clone()); } else InHere.Nodes.Add((TreeNode)FindMe.Clone()); } else { //if the item was found, check all children. foreach (TreeNode child in FindMe.Nodes) FindOrAdd(child, ref InHere); } } 

Again, this solution only works if you have unique paths ... with the extension, it also takes into account uniqueness at the case level.

I posted it here in the hope of helping someone who, like me, had to look for a solution for several days in a row without success and had to create my own.

+1
source

All Articles