开发者

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)

how to turn this to into a tree?

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:

  1. Split the parameters...

  2. Create one div for each (parameter1)

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜