EachOne
EachOne

Reputation: 101

Build Object Recursive

I have a Object which looks like the following obj.

var obj = [
  { id: 1, name: "animals" },
  { id: 2, name: "animals_cat" },
  { id: 3, name: "animals_dog" },
  { id: 4, name: "animals_weazle" },
  { id: 5, name: "animals_weazle_sand shadow weazle" },
  { id: 11, name: "fruits" },
  { id: 32, name: "fruits_banana" },
  { id: 10, name: "threes" },
  { id: 15, name: "cars" }
];

The Object should be converted into the following scheme:

var items = [
    { id: 11, name: "fruits", items: [
      { id: 32, name: "banana" }
      ]},
    { id: 10, name: "threes" },
    { id: 1, name: "animals", items: [
        { id: 2, name: "cat" },
        { id: 3, name: "dog" },
        { id: 4, name: "weazle", items: [
            { id: 5, name: "sand shadow weazle" }    
        ]}
    ]},
    { id: 15, name: "cars" }
];

I tried a lot but unfortunately without any success. I did $.each on obj, did a split('_') on it and pushed it to items. But how can I do it for unlimited depth and push it into the right category?

I'm happy for any help.

Upvotes: 0

Views: 46

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386654

Maybe this helps.

It works with Array.prototype.forEach for processing obj, Array.prototype.reduce for getting the right branch and Array.prototype.some for the right array element for inserting the new object.

This proposal works for sorted and consistent data.

var obj = [
        { id: 1, name: "animals" },
        { id: 2, name: "animals_cat" },
        { id: 3, name: "animals_dog" },
        { id: 4, name: "animals_weazle" },
        { id: 5, name: "animals_weazle_sand shadow weazle" },
        { id: 11, name: "fruits" },
        { id: 32, name: "fruits_banana" },
        { id: 10, name: "threes" },
        { id: 15, name: "cars" }
    ],
    tree = [];

obj.forEach(function (a) {
    var path = a.name.split('_'),
        o = {};
    o.id = a.id;
    path.reduce(function (r, b) {
        o.name = b;
        r.some(function (c) {
            if (c.name === b) {
                c.items = c.items || [];
                r = c.items;
                return true;
            }
        });
        return r;
    }, tree).push(o);
});

document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');

Update: Version for independent order of items.

var obj = [
        { id: 5, name: "animals_weazle_sand shadow weazle" },
        { id: 32, name: "fruits_banana" },
        { id: 1, name: "animals" },
        { id: 2, name: "animals_cat" },
        { id: 3, name: "animals_dog" },
        { id: 4, name: "animals_weazle" },
        { id: 11, name: "fruits" },
        { id: 10, name: "threes" },
        { id: 15, name: "cars" },
        { id: 999, name: "music_pop_disco_euro"}
    ],
    tree = [];
    
obj.forEach(function (item) {
    var path = item.name.split('_'),
        o = tree;

    path.forEach(function (a, i) {
        var oo = { name: a, items: [] },
            last = path.length - 1 === i,
            found = o.some(function (b) {
                if (b.name === a) {
                    if (last) {
                        b.id = item.id;
                        return true;
                    }
                    b.items = b.items || [];
                    o = b.items;
                    return true;
                }
            });
        if (!found) {
            if (last) {
                o.push({ id: item.id, name: a });                        
            } else {
                o.push(oo);
                o = oo.items;
            }
        }
    });
});

document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');

Upvotes: 3

Related Questions