'use strict';
function shuffle(array) {
var m = array.length, t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
function treeify(flat) {
var map = { __root__: { children: [] }};
flat.forEach(function (node) {
var
parentId = node.parent_id || '__root__',
id = node.id;
if (!map.hasOwnProperty(parentId)) {
map[parentId] = { element: null, children: [] };
}
if (!map.hasOwnProperty(id)) {
map[id] = { element: null, children: [] };
}
map[id].element = node;
map[parentId].children.push(map[id]);
});
return map.__root__.children;
}
function treeIndent(branch, cfg, decorator, indent)
{
indent = indent || [];
branch.forEach(function (node, i) {
decorator(node.element, indent.concat(
i === branch.length - 1 ? cfg.isLastChild : cfg.hasNextSibling
));
treeIndent(node.children, cfg, decorator, indent.concat(
i === branch.length - 1 ? cfg.ancestorIsLastChild : cfg.ancestorHasNextSibling
));
});
}
var input = [
{ id: 1, parent_id: null, name: 'root' },
{ id: 2, parent_id: 1, name: 'bar' },
{ id: 5, parent_id: 2, name: 'baz' },
{ id: 6, parent_id: 5, name: 'qux' },
{ id: 7, parent_id: 6, name: 'quux' },
{ id: 8, parent_id: 6, name: 'corge' },
{ id: 9, parent_id: 2, name: 'but' },
{ id: 3, parent_id: 1, name: 'fizz' },
{ id: 4, parent_id: 1, name: 'buzz' }
];
var log = document.getElementById('log');
treeIndent(treeify(shuffle(input)), {
hasNextSibling: '├',
isLastChild: '└',
ancestorHasNextSibling: '│',
ancestorIsLastChild: ' '
}, function (element, indent) {
log.innerHTML += indent.join(' ') + ' ' + element.name + "\n";
});
<pre id="log"></pre>