JS Prevent duplicates when using .push()

JS Prevent duplicates when using .push()

I grab a list of data from the server and I have to convert it.
Part of this is turning it into a 3 dimensional array. After the “myArr[i].children.push(temp);” it leaves copies of the objects that were pushed in the root of the array. Can I either push without copying or how would I delete these? (I have underscore js included, I know they have good array functions :))

for (var i = 0; i < myArr.length; i++) {
    myArr[i].children = [];
    for (var q = 0; q < myArr.length; q++) {
        if (myArr[i].id == myArr[q].parentid) {
            var temp = {
                id: myArr[q].id,
                index: myArr[q].index,
                text: myArr[q].text
            }
            myArr[i].children.push(temp);
        };
    };  
};

The Data

[{
    "id": "5",
    "parentid": "0",
    "text": "Device Guides",
    "index": "0"
}, {
    "id": "6",
    "parentid": "0",
    "text": "Pre-Sales Evaluation",
    "index": "1"
}, {
    "id": "7",
    "parentid": "0",
    "text": "Router Setup Guides",
    "index": "2"
}, {
    "id": "9",
    "parentid": "7",
    "text": "Sonicwall",
    "index": "0"
}, {
    "id": "10",
    "parentid": "5",
    "text": "Grandstream GXP-21XX",
    "index": "1"
}, {
    "id": "11",
    "parentid": "5",
    "text": "Polycom Soundstation/Soundpoint",
    "index": "2"
}, {
    "id": "12",
    "parentid": "7",
    "text": "Cisco",
    "index": "1"
}, {
    "id": "15",
    "parentid": "0",
    "text": "Post-Sales Implementation Check List",
    "index": "7"
}, {
    "id": "16",
    "parentid": "15",
    "text": "Porting and New Number Details",
    "index": "0"
}, {
    "id": "18",
    "parentid": "15",
    "text": "Partner Setup",
    "index": "1"
}, {
    "id": "19",
    "parentid": "15",
    "text": "test",
    "index": "2"
}, {
    "id": "20",
    "parentid": "0",
    "text": "test",
    "index": "11"
}, {
    "id": "21",
    "parentid": "15",
    "text": "test",
    "index": "3"
}, {
    "id": "23",
    "parentid": "5",
    "text": "New Polycom",
    "index": "0"
}, {
    "id": "24",
    "parentid": "0",
    "text": "Test Markup",
    "index": "14"
}, {
    "id": "25",
    "parentid": "0",
    "text": "test",
    "index": "15"
}]

After it is formated:

{
    "children": [{
        "id": "5",
        "parentid": "0",
        "text": "Device Guides",
        "index": "1",
        "children": [{
            "id": "10",
            "index": "0",
            "text": "Grandstream GXP-21XX"
        }, {
            "id": "11",
            "index": "1",
            "text": "Polycom Soundstation/Soundpoint"
        }, {
            "id": "23",
            "index": "2",
            "text": "New Polycom"
        }]
    }, {
        "id": "6",
        "parentid": "0",
        "text": "Pre-Sales Evaluation",
        "index": "0",
        "children": []
    }, {
        "id": "7",
        "parentid": "0",
        "text": "Router Setup Guides",
        "index": "2",
        "children": [{
            "id": "9",
            "index": "0",
            "text": "Sonicwall"
        }, {
            "id": "12",
            "index": "1",
            "text": "Cisco"
        }]
    }, {
        "id": "9",
        "parentid": "7",
        "text": "Sonicwall",
        "index": "0",
        "children": []
    }, {
        "id": "10",
        "parentid": "5",
        "text": "Grandstream GXP-21XX",
        "index": "0",
        "children": []
    }, {
        "id": "11",
        "parentid": "5",
        "text": "Polycom Soundstation/Soundpoint",
        "index": "1",
        "children": []
    }, {
        "id": "12",
        "parentid": "7",
        "text": "Cisco",
        "index": "1",
        "children": []
    }, {
        "id": "15",
        "parentid": "0",
        "text": "Post-Sales Implementation Check List",
        "index": "7",
        "children": [{
            "id": "16",
            "index": "0",
            "text": "Porting and New Number Details"
        }, {
            "id": "18",
            "index": "1",
            "text": "Partner Setup"
        }, {
            "id": "19",
            "index": "2",
            "text": "test"
        }, {
            "id": "21",
            "index": "3",
            "text": "test"
        }]
    }, {
        "id": "16",
        "parentid": "15",
        "text": "Porting and New Number Details",
        "index": "0",
        "children": []
    }, {
        "id": "18",
        "parentid": "15",
        "text": "Partner Setup",
        "index": "1",
        "children": []
    }, {
        "id": "19",
        "parentid": "15",
        "text": "test",
        "index": "2",
        "children": []
    }, {
        "id": "20",
        "parentid": "0",
        "text": "test",
        "index": "11",
        "children": []
    }, {
        "id": "21",
        "parentid": "15",
        "text": "test",
        "index": "3",
        "children": []
    }, {
        "id": "23",
        "parentid": "5",
        "text": "New Polycom",
        "index": "2",
        "children": []
    }, {
        "id": "24",
        "parentid": "0",
        "text": "Test Markup",
        "index": "14",
        "children": []
    }, {
        "id": "25",
        "parentid": "0",
        "text": "test",
        "index": "15",
        "children": []
    }]
}

Here you go

tree = {0: {children: []}}

data.forEach(function(x) {
    x.children = tree[x.id] ? tree[x.id].children : [];
    tree[x.id] = x;

    if(!tree[x.parentid])
        tree[x.parentid] = {children: []}
    tree[x.parentid].children.push(x)
})

result = tree[0].children

This solution is linear (iterates over the array just once) and doesn’t require any pre-sorting.

http://jsfiddle.net/U47WY/

and here’s how to convert the tree back to the linear array:

function flatten(source) {
    return source.reduce(function(a, x) {
        var children = x.children;
        delete x.children;
        return a.concat([x], flatten(x.children))
    }, []);
}

Following on from a friendly discussion in the comments :

var zeroObj = {"children":[]};
for (var i = 0; i < myArr.length; i++) {
    if(myArr[i].parentid === 0) {
        zeroObj.children.push(myArr[i]);
    } else {
        for (var q = 0; q < myArr.length; q++) {
            if (myArr[i].parentid == myArr[q].id) {
                myArr[q].children = myArr[q].children || [];
                myArr[q].children.push(myArr[i]);
            };
        }; 
    }
};
.
.
.
.