0

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.

EachOne
  • 91
  • 3
  • 1
    Post some attempts at solving the problem and perhaps someone may help you. – Robert Moskal Oct 24 '15 at 16:04
  • Considering that you're changing the structure to something more treelike, there's little reason to keep the same ID. –  Oct 24 '15 at 16:04
  • Maybe this helps: [Access / process (nested) objects, arrays or JSON](http://stackoverflow.com/q/11922383/218196) – Felix Kling Oct 24 '15 at 16:22
  • 1
    @Rollo that doesn't make sense if they are stored in a database with id as key – charlietfl Oct 24 '15 at 16:37
  • What if there is an element that has a parent `name` that is not existent in your array - how should an id be found for it? – Bergi Oct 24 '15 at 17:02
  • @Bergi, `id` looks like an additional information for the element. for the tree building the `id` is not necessary. – Nina Scholz Oct 24 '15 at 19:29

1 Answers1

3

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>');
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392