This code snippet is designed to bring you very close to your desired outcome. By wrapping the JSON result in an array, the getNode function is simplified, although you can opt to directly target the [0] index of the array instead. Initially, there was an attempt to adhere to JSLint standards (hence the use of i = i + 1 instead of i++), but this approach was abandoned midway for the sake of clarity and cleanliness. ;)
http://jsfiddle.net/Zcyca/
var i, j, k, arr =
[
["a","b","c"],
["a","b","d"],
["c","b","e"],
["c","b","f"]
];
var results = [];
var last = results;
for(i = 0; i < arr.length; i = i + 1) {
var subArr = arr[i];
var parentURI = subArr[0], middleURI = subArr[1], childURI = subArr[2];
var parent, middle, child;
// Find parent or create parent
parent = getNode(results, parentURI);
if(parent === null) {
results.push({"uri": parentURI, "subItems": []});
parent = results[results.length-1];
}
if(typeof parent["subItems"] === "undefined") {
parent["subItems"] = [];
}
// Find middle or create middle
middle = getNode(parent["subItems"], middleURI);
if(middle === null) {
parent["subItems"].push({"uri": middleURI, "subItems": []});
middle = parent["subItems"][parent["subItems"].length-1];
}
if(typeof middle["subItems"] === "undefined") {
middle["subItems"] = [];
}
// Find child or create child
child = getNode(middle["subItems"], childURI);
if(child === null) {
middle["subItems"].push({"uri": childURI});
//child = middle["subItems"][middle["subItems"].length-1];
}
}
document.write(JSON.stringify(results));
function getNode(arr, uri) {
var node = null;
(function recurseArr(arr) {
for(var i = 0; i < arr.length; i = i + 1) {
var obj = arr[i];
if(obj["uri"] === uri) {
node = arr[i];
break;
} else if(typeof obj["subItems"] !== "undefined") {
recurseArr(obj["subItems"]);
}
}
})(arr);
return node;
}