17

I have an array of strings that describe the parent/child relationship by being delimited with dashes. So, if Bob's boss was Jim and Jim's boss was Fred, Bob's entry in the array would be "Fred-Jim-Bob" and Jim's entry would be "Fred-Jim." I don't have the ability to change the way the data is coming in so I was looking for help as far as the best way of turning these values into JSON similar to this:

{
    "name": "Fred",
    "children": {
        "name": "Jim",
        "children": {
            "name": "Bob"
        }
    }
}

Any help would be greatly appreciated. Thanks.

Munzilla
  • 3,805
  • 5
  • 31
  • 35
  • can you give an example of the input string? also, does it go down infinite levels, or is it limited to 3? – Jason Jun 03 '11 at 21:21
  • Well it would be an array of strings like the ones shown above. So for the json I mentioned above the array might be: var emp = new Array("Fred-Jim","Fred","Fred-Jim-Bob"); and yes it could be more or less than 3. – Munzilla Jun 03 '11 at 21:28

1 Answers1

35
var input = ["Fred-Jim-Bob", "Fred-Jim", "Fred-Thomas-Rob", "Fred"];
var output = [];
for (var i = 0; i < input.length; i++) {
    var chain = input[i].split("-");
    var currentNode = output;
    for (var j = 0; j < chain.length; j++) {
        var wantedNode = chain[j];
        var lastNode = currentNode;
        for (var k = 0; k < currentNode.length; k++) {
            if (currentNode[k].name == wantedNode) {
                currentNode = currentNode[k].children;
                break;
            }
        }
        // If we couldn't find an item in this list of children
        // that has the right name, create one:
        if (lastNode == currentNode) {
            var newNode = currentNode[k] = {name: wantedNode, children: []};
            currentNode = newNode.children;
        }
    }
}

output JSONifies as:

[{
    "name": "Fred",
    "children": [{
        "name": "Jim",
        "children": [{
            "name": "Bob",
            "children": []
        }]
    }, {
        "name": "Thomas",
        "children": [{
            "name": "Rob",
            "children": []
        }]
    }]
}]
Gijs
  • 5,201
  • 1
  • 27
  • 42
  • 1
    The example input happens to have strings that go up to 3 levels, but you're welcome to add more. Try loading the example and making one of the strings say `"Fred-Jim-Bob-Mark"`. You'll see it works fine, too. Mathematical infinity it probably won't handle, but anything within reasonable bounds when browser memory is concerned should work. – Gijs Jun 03 '11 at 21:54
  • Yes, I'm using this to parse out data for a company's org chart, so I don't need INFINITE levels, but prepared for more than 3. – Munzilla Jun 06 '11 at 13:33
  • 3
    Works great, is there anyway you can add comments this code? I'm getting lost when debugging where you're setting currentNode = currentNode[k] = currentNode[k].children or currentNode = newNode.children which I believe is one of the most important steps in this algorithm. – LeLong37 Jul 16 '14 at 15:11
  • I know this is super old now but this isn't working for me. Isn't 'K' out of scope by the time that you try and reuse it in the final if statement? – thomasters Mar 12 '23 at 21:25
  • Still works fine for me (just tested in a current browser's JS console). In JS `var` is hoisted, so no, it won't be out of scope. If you're switching to `let` or `const` or using some language other than JS, or babel or a similar thing that transforms your JS, perhaps that is breaking it? – Gijs Mar 13 '23 at 23:07