Ashish Rawat
Ashish Rawat

Reputation: 3513

How to convert array of arrays into deep nested tree view

I'm building a tree view by converting array of paths into tree view data structure. Here's what I want to do:

// routes are sorted.
let routes = [
    ['top', '1.jpg'],
    ['top', '2.jpg'],
    ['top', 'unsplash', 'photo.jpg'],
    ['top', 'unsplash', 'photo2.jpg'],
    ['top', 'foo', '2.jpg'],
    ['top', 'foo', 'bar', '1.jpg'],
    ['top', 'foo', 'bar', '2.jpg']
];

into 

let treeview = {
  name: 'top', child: [
    {name: '1.jpg', child: []},
    {name: '2.jpg', child: []},
    {name: 'unsplash', child: [
        {name: 'photo.jpg', child: []},
        {name: 'photo2.jpg', child: []}
    ]},
    {name: 'foo', child: [
        {name: '2.jpg', child: []},
        {name: 'bar', child: [
            {name: '1.jpg', child: []},
            {name: '2.jpg', child: []}
        ]}
    ]}
]}

Now I've successfully convert single array of items via this method, but unable to do so for multiple array. Note also, nested treeview doesn't contain duplicate.

function nest(arr) {
    let out = [];
    arr.map(it => {
        if(out.length === 0) out = {name: it, child: []}
        else {
            out = {name: it, child: [out]}
        }
    });
    return out;
}

Upvotes: 6

Views: 1088

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386570

You could use a nested hash table for the access for the routes and take an array as result set. If you have only one root element, you could take the first element of the result array.

var routes = [['top', '1.jpg'], ['top', '2.jpg'], ['top', 'unsplash', 'photo.jpg'], ['top', 'unsplash', 'photo2.jpg'], ['top', 'foo', '2.jpg'], ['top', 'foo', 'bar', '1.jpg'], ['top', 'foo', 'bar', '2.jpg']],
    result = [],
    temp = { _: result };

routes.forEach(function (path) {
    path.reduce(function (level, key) {
        if (!level[key]) {
            level[key] = { _: [] };
            level._.push({ name: key, children: level[key]._ });
        }
        return level[key];
    }, temp);
});

console.log(result);    
.as-console-wrapper { max-height: 100% !important; top: 0; }

ES6 without a temporary object, but with a seach of a named object with the path name.

var routes = [['top', '1.jpg'], ['top', '2.jpg'], ['top', 'unsplash', 'photo.jpg'], ['top', 'unsplash', 'photo2.jpg'], ['top', 'foo', '2.jpg'], ['top', 'foo', 'bar', '1.jpg'], ['top', 'foo', 'bar', '2.jpg']],
    result = [];

routes.forEach(function (path) {
    path.reduce(function (level, key) {
        var temp = level.find(({ name }) => key === name);
        if (!temp) {
            temp = { name: key, children: [] };
            level.push(temp);
        }
        return temp.children;
    }, result);
});

console.log(result);    
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 8

Related Questions