how to turn this to into a tree?
I was doing a challenge of building a tree from all html elements. And I am 90% done, but I got stuck...
How do I change开发者_运维技巧 this string into a tree?:
mystring= "red1/(none)-red2/red1-blue1/red2-blue2/red2-blue3/red2-red3/red1-red4/red3-red5/red4-red6/red5-blue4/red6";
After splitting them by "-" we will have:
10 groups of -> (parameter1)/(parameter2)
The first parameter it is the object, The second parameter is the 'in-what-it-will-be-contained'
I have no idea how to move every 'parameter1' inside 'parameter2'. (note: sometimes the parameter1 will be the parameter2 of a parameter1)
Visual example of what I mean with a parameter is inside another parameter: (this example uses exactly the string above)
Probably we should use arrays?, idk... I am totally lost :sadface:
I think this is a little more concise and straight forward. It uses an object as a dictionary to lookup the parent, rather than a function that has to recursively iterate the tree to find the parent. That recursive function is expensive. An object lookup is quick.
First, for convenience, I'd define an object type:
function TreeNode(name) {
this.Name = name;
this.Children = [];
}
Then I'd add a method to do the work. This parses your tree string:
TreeNode.ParseTree = function (treeString) {
var root = new TreeNode("");
var nodes = {};
var pairs = treeString.split("-");
pairs.forEach(function(pair) {
var parts = pair.split("/");
var parentName = parts[1];
var childName = parts[0];
var node;
if (parentName == "(none)") {
node = root;
root.Name = childName;
}
else {
node = new TreeNode(childName);
nodes[parentName].Children.push(node);
}
nodes[childName] = node;
});
return root;
};
That's it! Now, to get visual representations of your tree, you can add some prototype methods to TreeNode
. First, override .toString()
:
TreeNode.prototype.toString = function(indent) {
indent = indent || "";
var strings = [indent + this.Name];
this.Children.forEach(function(child) {
strings.push(child.toString(indent + " "));
});
return strings.join("\n");
};
Then, add a .Render()
method to display the tree within a web page:
TreeNode.prototype.Render = function(container) {
var nodeEl = container.appendChild(document.createElement("div"));
nodeEl.className = "treeNode";
var nameEl = nodeEl.appendChild(document.createElement("div"));
nameEl.className = "treeNodeName";
nameEl.appendChild(document.createTextNode(this.Name));
var childrenEl = nodeEl.appendChild(document.createElement("div"));
childrenEl.className = "treeNodeChildren";
this.Children.forEach(function(child) {
child.Render(childrenEl);
});
return nodeEl;
};
Here it is in action: http://jsfiddle.net/gilly3/wwFBx/
Edit: I didn't notice the jQuery tag in your post, here's a render method that's all jQuery, and produces simpler HTML which you seem to imply is what you want:
TreeNode.prototype.Render = function(container) {
var el = $("<div>").appendTo(container).text(this.Name);
$.each(this.Children, function() {
this.Render(el);
});
return el;
};
This JSFiddle uses jQuery, even replacing Array.forEach
with $.each
: http://jsfiddle.net/wwFBx/1/
As an alternative, you might consider just serializing your tree as JSON. Eg:
"{\"Name\":\"red1\",\"Children\":[{\"Name\":\"red2\",\"Children\":[{\"Name\":\"blue1\",\"Children\":[]},{\"Name\":\"blue2\",\"Children\":[]},{\"Name\":\"blue3\",\"Children\":[]}]},{\"Name\":\"red3\",\"Children\":[{\"Name\":\"red4\",\"Children\":[{\"Name\":\"red5\",\"Children\":[{\"Name\":\"red6\",\"Children\":[{\"Name\":\"blue4\",\"Children\":[]}]}]}]}]}]}"
or maybe:
"{\"red1\":{\"red2\":{\"blue1\":{},\"blue2\":{},\"blue3\":{}},\"red4\":{\"red5\":{\"red6\":{\"blue4\":{}}}}}}"
Parse the string via JSON.parse()
.
Disclaimer: I've referenced Array.forEach()
and JSON.parse()
which are built-in to modern browsers but are not supported by older browsers. To enable these functions in older browsers, see this documentation on Array.forEach()
and this shim for JSON.parse()
.
Here's about how I would do it, using an array of "unplaced" elements and looping through it until they're all placed:
var str = "red1/(none)-red2/red1-blue1/red2-blue2/red2-blue3/red2-red3/red1-red4/red3-red5/red4-red6/red5-blue4/red6";
var unplaced = [];
var tree = null;
var elements = str.split(/[\/\-]/);
function findNodeByName(nodeName, context) {
if(context.name === nodeName) return context;
for(var i = 0; i < context.children.length; i++) {
var subSearch = findNodeByName(nodeName, context.children[i]);
if(subSearch) return subSearch;
}
return null;
}
var element, node, parent, thisElement, i;
for(i = 0; node = elements[i]; i += 2) {
node = elements[i];
parent = elements[i + 1];
thisElement = {name: node, children: []};
if(!tree && parent === '(none)') {
tree = thisElement;
} else if(tree) {
var parentNode = findNodeByName(parent, tree);
if(parentNode) {
parentNode.children.push(thisElement);
} else {
unplaced.push(thisElement);
}
}
}
var oldLength;
while(unplaced.length) {
oldLength = unplaced.length;
for(i = 0; element = unplaced[i]; i++) {
var parentNode = findNodeByName(parent, tree);
if(parentNode) {
parentNode.children.push(element);
unplaced.splice(i, 1);
i--;
}
}
if(oldLength === unplaced.length) {
throw new SyntaxError("The string is not a valid tree.");
}
}
// The result is contained in "tree".
You can see the result at: http://jsfiddle.net/minitech/tJSpN/
One with a function: http://jsfiddle.net/minitech/tJSpN/1/
And one with more error-checking: http://jsfiddle.net/minitech/tJSpN/2/
Actually, I found a simpler/shorter/neater way using the JQuery function AppendTo()
We just need to:
Split the parameters...
Create one div for each (parameter1)
Use a loop to move every (parameter1) inside (parameter2) using the AWESOME AppendTo() function that JQuery offers
The best thing is that they are actually inside them, so you can easily put a Hide/Show effect to make a cool effect
You may try to create tree nodes of the form :
node = {
str:"red1",
subBranches : new Array()
}
Once you have that, you may add the sub-branches iterating through the array, adding such nodes for each found correct couple, and removing the couples already placed in rootNode.subBranches
. Then you recursively do the same for every sub-branche.
精彩评论