I have array of objects, each object must have key and title, but children is optional, and it can be nested, i can have children inside of children many times. I want to remove some object by provided key value (for example key 677). I tried with filter but i only remove first level. Also have tried recursion, but not sure if i did it right.
const data = [{
key: '1',
title: 'title 1',
children: [{
key: '098',
title: 'hey',
children: [{
key: '677',
title: 'child'
}]
}]
},
{
key: '123',
title: 'tile 111'
},
{
key: '345',
title: 'something'
}
];
const rem = '677';
const del = (el) => {
if (!el.children) {
return el.key !== rem;
} else {
if (el.key !== rem) {
del(el.children);
return el;
}
}
};
const res = data.filter((el) => {
return del(el);
});
console.log(res);
I guess your existing solution is like
const data = [
{
key: '1',
title: 'title 1',
children: [{
key: '098',
title: 'hey',
children: [{ key: '677', title: 'child'}]
}]
},
{ key: '123', title: 'tile 111' },
{ key: '345', title: 'something' }
];
function removeByKey(arr, removingKey){
return arr.filter( a => a.key !== removingKey);
}
So it works on the first level but not deeply.
Just change it like that will do the jobs
function removeByKey(arr, removingKey){
return arr.filter( a => a.key !== removingKey).map( e => {
return { ...e, children: removeByKey(e.children || [], removingKey)}
});
}
Little warning, children property will not be set to [] for every item not having any children.
So how it works? Well instead of keeping acceptable items as they are, we make a copy using {...e} that's equivalent to {key:e.key, title:e.title, children:e.children} in this case.
We know force to override the property children with removeByKey(e.children || [], removingKey), so we call the method recursively. Not the function works deeeply.
I would use a recursion approach with findIndex and splice. Using some will allow the code to exit without running through the entire tree.
const data = [{
key: '1',
title: 'title 1',
children: [{
key: '098',
title: 'hey',
children: [{
key: '677',
title: 'child'
}]
}]
},
{
key: '123',
title: 'tile 111'
},
{
key: '345',
title: 'something'
}
];
const removeKey = (data, key) => {
// look to see if object exists
const index = data.findIndex(x => x.key === key);
if (index > -1) {
data.splice(index, 1); // remove the object
return true
} else {
// loop over the indexes of the array until we find one with the key
return data.some(x => {
if (x.children) {
return removeKey(x.children, key);
} else {
return false;
}
})
}
}
console.log(removeKey(data, '677'))
console.log(JSON.stringify(data));
You can use some simple recursion to do the trick:
const data = [
{
key: '1',
title: 'title 1',
children: [
{
key: '098',
title: 'hey',
children: [{ key: '677', title: 'child'}]
}
]
},
{ key: '123', title: 'tile 111' },
{ key: '345', title: 'something' }
];
function removeByKey(key, arr) {
// loop through all items of array
for(let i = 0; i < arr.length; i++) {
// if array item has said key, then remove it
if(arr[i].key === key) {
arr.splice(i, 1);
} else if(typeof(arr[i].children) !== "undefined") {
// if object doesn't have desired key but has children, call this function
// on the children array
removeByKey(key, arr[i].children);
}
}
}
removeByKey('098', data);
console.log(data);
This may be a little easier to understand than the other answer provided.
I have an array and I want to delete an object in it.
I only have the complete object and I want to delete from the array inside it.
Object = {Comments: [{text: 'hello', x:200, y:100},
{text: 'hi', x:565, y:454},
{text: 'Hola', x:454, y:235}
]
};
I want to delete this object :
toDelete = {text: 'hi', x:565, y:454}
How can I do this?
You can use
Object.Comments.splice(1, 1);
But you should also give your variable a different name and use let or var.
You can use filter to remove an item from an array:
const myArray = [
{ text: 'one', digit: 1 },
{ text: 'two', digit: 2 },
{ text: 'three', digit: 3 }
];
const filteredArray = myArray.filter(item => {
return item.text !== 'two' && item.digit !== 2
});
console.log(filteredArray); // [ { text: 'one', digit: 1 }, { text: 'three', digit: 3 } ]
You should use a unique id for comments array.
var Object = {
Comments: [{
id: 1,
text: 'hello',
x: 200,
y: 100
},
{
id: 2,
text: 'hi',
x: 565,
y: 454
},
{
id: 3,
text: 'Hola',
x: 454,
y: 235
}
]
};
const {
Comments
} = Object;
function deleteComment = (itemArray, id) => {
return itemArray.filter(itm => {
return itm.id !== id
})
}
const filterdArray = deleteComment(Comments, passYourTargetId);
// in this filterdArray you get without that item you want to remove and it work with immutable way
I've managed to copy the intended object into the intended location (my code is below), but how do I move it? So it will not exist in the original location any more.
So in my example, I want to take the object with id of 14 (very bottom of the object) and move it into the children of the object with id of 3 (towards the top).
I know I need to modify this line: item.children.push(itemToMove) in my moveItem function, but some reason I can't think of it.
Also sorry about the very big/nested object, I wanted to make sure to cover a deeply nested object.
const myObj = [
{
id: 1,
name: '1',
children: [
{
id: 2,
name: '2',
children: [
{
id: 3,
name: '3',
children: []
}
]
},
{
id: 4,
name: '4',
children: [
{
id: 5,
name: '5',
children: [
{
id: 6,
name: '6',
children: [
{
id: 7,
name: '7',
children: []
}
]
}
]
}
]
},
]
},
{
id: 8,
name: '8',
children: [
{
id: 9,
name: '9',
children: [
{
id: 10,
name: '10',
children: []
}
]
},
{
id: 11,
name: '11',
children: [
{
id: 12,
name: '12',
children: [
{
id: 13,
name: '13',
children: [
{
id: 14,
name: '14',
children: []
}
]
}
]
}
]
},
]
}
]
let itemToMove = {
id: 14,
name: '14',
children: []
}
// move item, return updated obj
function moveItem(itemToMove, obj, parentId) {
for (let i=0;i<obj.length;i++) {
const value = obj[i];
const item = search(obj[i], parentId);
if (item) {
item.children.push(itemToMove); // pushed into children, but need to move not duplicate in
break;
}
}
function search(obj, id) {
if (obj.id === id) {
return obj;
}
for (let i=0;i<obj.children.length;i++) {
const possibleResult = search(obj.children[i], id);
if (possibleResult) {
return possibleResult;
}
}
}
return obj;
};
console.log(moveItem(itemToMove, myObj, 3))
I would probably do something like this, taking into account that if the insert fails, you should have some kind of way to re-instate the data. I also used ES6 which is different to your code, but it gives you some kind of idea.
let parent
function removeItem (obj, itemToFind) {
// Loop the object
obj.find((e, index) => {
// If the id's match remove from the parent if it exists otherwise from the object as its at root level
if (e.id === itemToFind.id) {
if (parent) {
parent.children.splice(index, 1)
} else {
obj.splice(index, 1)
}
// break the loop once returned true. Change find to forEach to remove all instances with id if allowing multiples
return true
}
// recurse
else if (e.children && e.children.length > 0) {
parent = e
return removeItem(e.children, itemToFind)
}
})
}
// move item, return updated obj
function moveItem (itemToMove, obj, parentId) {
for (let i = 0; i < obj.length; i++) {
const value = obj[i]
const item = search(obj[i], parentId)
if (item) {
item.children.push(itemToMove) // pushed into children, but need to move not duplicate in
break
}
}
function search (obj, id) {
if (obj.id === id) {
return obj
}
for (let i = 0; i < obj.children.length; i++) {
const possibleResult = search(obj.children[i], id)
if (possibleResult) {
return possibleResult
}
}
}
return obj
};
removeItem(myObj, itemToMove)
moveItem(itemToMove, myObj, 3)
I have the following array (that's actually coming from a backend service):
const flat: Item[] = [
{ id: 'a', name: 'Root 1', parentId: null },
{ id: 'b', name: 'Root 2', parentId: null },
{ id: 'c', name: 'Root 3', parentId: null },
{ id: 'a1', name: 'Item 1', parentId: 'a' },
{ id: 'a2', name: 'Item 1', parentId: 'a' },
{ id: 'b1', name: 'Item 1', parentId: 'b' },
{ id: 'b2', name: 'Item 2', parentId: 'b' },
{ id: 'b2-1', name: 'Item 2-1', parentId: 'b2' },
{ id: 'b2-2', name: 'Item 2-2', parentId: 'b2' },
{ id: 'b3', name: 'Item 3', parentId: 'b' },
{ id: 'c1', name: 'Item 1', parentId: 'c' },
{ id: 'c2', name: 'Item 2', parentId: 'c' }
];
where Item is:
interface Item {
id: string;
name: string;
parentId: string;
};
In order to be compatible with a component that displays a tree (folder like) view, it needs to be transformed into:
const treeData: NestedItem[] = [
{
id: 'a',
name: 'Root 1',
root: true,
count: 2,
children: [
{
id: 'a1',
name: 'Item 1'
},
{
id: 'a2',
name: 'Item 2'
}
]
},
{
id: 'b',
name: 'Root 2',
root: true,
count: 5, // number of all children (direct + children of children)
children: [
{
id: 'b1',
name: 'Item 1'
},
{
id: 'b2',
name: 'Item 2',
count: 2,
children: [
{ id: 'b2-1', name: 'Item 2-1' },
{ id: 'b2-2', name: 'Item 2-2' },
]
},
{
id: 'b3',
name: 'Item 3'
},
]
},
{
id: 'c',
name: 'Root 3',
root: true,
count: 2,
children: [
{
id: 'c1',
name: 'Item 1'
},
{
id: 'c2',
name: 'Item 2'
}
]
}
];
where NestedItem is:
interface NestedItem {
id: string;
name: string;
root?: boolean;
count?: number;
children?: NestedItem[];
}
All I've tried so far is something like:
// Get roots first
const roots: NestedItem[] = flat
.filter(item => !item.parentId)
.map((item): NestedItem => {
return { id: item.id, name: item.name, root: true }
});
// Add "children" to those roots
const treeData = roots.map(node => {
const children = flat
.filter(item => item.parentId === node.id)
.map(item => {
return { id: item.id, name: item.name }
});
return {
...node,
children,
count: node.count ? node.count + children.length : children.length
}
});
But this only gets the first level of children, of course (direct children of root nodes). It somehow needs to be recursive, but I have no idea how to accomplish that.
Making no assumptions about the order of the flattened array or how deep a nested object can go:
Array.prototype.reduce is flexible enough to get this done. If you are not familiar with Array.prototype.reduce I recommend reading this. You could accomplish this by doing the following.
I have two functions that rely on recursion here: findParent and checkLeftOvers. findParent attempts to find the objects parent and returns true or false based on whether it finds it. In my reducer I add the current value to the array of left overs if findParent returns false. If findParent returns true I call checkLeftOvers to see if any object in my array of left overs is the child of the object findParent just added.
Note: I added { id: 'b2-2-1', name: 'Item 2-2-1', parentId: 'b2-2'} to the flat array to demonstrate that this will go as deep as you'd like. I also reordered flat to demonstrate that this will work in that case as well. Hope this helps.
const flat = [
{ id: 'a2', name: 'Item 1', parentId: 'a' },
{ id: 'b2-2-1', name: 'Item 2-2-1', parentId: 'b2-2'},
{ id: 'a1', name: 'Item 1', parentId: 'a' },
{ id: 'a', name: 'Root 1', parentId: null },
{ id: 'b', name: 'Root 2', parentId: null },
{ id: 'c', name: 'Root 3', parentId: null },
{ id: 'b1', name: 'Item 1', parentId: 'b' },
{ id: 'b2', name: 'Item 2', parentId: 'b' },
{ id: 'b2-1', name: 'Item 2-1', parentId: 'b2' },
{ id: 'b2-2', name: 'Item 2-2', parentId: 'b2' },
{ id: 'b3', name: 'Item 3', parentId: 'b' },
{ id: 'c1', name: 'Item 1', parentId: 'c' },
{ id: 'c2', name: 'Item 2', parentId: 'c' }
];
function checkLeftOvers(leftOvers, possibleParent){
for (let i = 0; i < leftOvers.length; i++) {
if(leftOvers[i].parentId === possibleParent.id) {
delete leftOvers[i].parentId
possibleParent.children ? possibleParent.children.push(leftOvers[i]) : possibleParent.children = [leftOvers[i]]
possibleParent.count = possibleParent.children.length
const addedObj = leftOvers.splice(i, 1)
checkLeftOvers(leftOvers, addedObj[0])
}
}
}
function findParent(possibleParents, possibleChild) {
let found = false
for (let i = 0; i < possibleParents.length; i++) {
if(possibleParents[i].id === possibleChild.parentId) {
found = true
delete possibleChild.parentId
if(possibleParents[i].children) possibleParents[i].children.push(possibleChild)
else possibleParents[i].children = [possibleChild]
possibleParents[i].count = possibleParents[i].children.length
return true
} else if (possibleParents[i].children) found = findParent(possibleParents[i].children, possibleChild)
}
return found;
}
const nested = flat.reduce((initial, value, index, original) => {
if (value.parentId === null) {
if (initial.left.length) checkLeftOvers(initial.left, value)
delete value.parentId
value.root = true;
initial.nested.push(value)
}
else {
let parentFound = findParent(initial.nested, value)
if (parentFound) checkLeftOvers(initial.left, value)
else initial.left.push(value)
}
return index < original.length - 1 ? initial : initial.nested
}, {nested: [], left: []})
console.log(nested)
You could a standard approach for a tree which takes a single loop and stores the relation between child and parent and between parent and child.
For having root properties you need an additional check.
Then take an iterative and recursive approach for getting count.
var data = [{ id: 'a', name: 'Root 1', parentId: null }, { id: 'b', name: 'Root 2', parentId: null }, { id: 'c', name: 'Root 3', parentId: null }, { id: 'a1', name: 'Item 1', parentId: 'a' }, { id: 'a2', name: 'Item 1', parentId: 'a' }, { id: 'b1', name: 'Item 1', parentId: 'b' }, { id: 'b2', name: 'Item 2', parentId: 'b' }, { id: 'b3', name: 'Item 3', parentId: 'b' }, { id: 'c1', name: 'Item 1', parentId: 'c' }, { id: 'c2', name: 'Item 2', parentId: 'c' }, { id: 'b2-1', name: 'Item 2-1', parentId: 'b2' }, { id: 'b2-2', name: 'Item 2-2', parentId: 'b2' },],
tree = function (data, root) {
function setCount(object) {
return object.children
? (object.count = object.children.reduce((s, o) => s + 1 + setCount(o), 0))
: 0;
}
var t = {};
data.forEach(o => {
Object.assign(t[o.id] = t[o.id] || {}, o);
t[o.parentId] = t[o.parentId] || {};
t[o.parentId].children = t[o.parentId].children || [];
t[o.parentId].children.push(t[o.id]);
if (o.parentId === root) t[o.id].root = true; // extra
});
setCount(t[root]); // extra
return t[root].children;
}(data, null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Assuming that the flat items array is always sorted like in your case (parents nodes are sorted before children nodes). The code below should do the work.
First, I build the tree without the count properties using reduce on the array to build a map to keeping a track of every node and linking parents to children:
type NestedItemMap = { [nodeId: string]: NestedItem };
let nestedItemMap: NestedItemMap = flat
.reduce((nestedItemMap: NestedItemMap, item: Item): NestedItemMap => {
// Create the nested item
nestedItemMap[item.id] = {
id: item.id,
name: item.name
}
if(item.parentId == null){
// No parent id, it's a root node
nestedItemMap[item.id].root = true;
}
else{
// Child node
let parentItem: NestedItem = nestedItemMap[item.parentId];
if(parentItem.children == undefined){
// First child, create the children array
parentItem.children = [];
parentItem.count = 0;
}
// Add the child node in it's parent children
parentItem.children.push(
nestedItemMap[item.id]
);
parentItem.count++;
}
return nestedItemMap;
}, {});
The fact that the parents node always come first when reducing the array ensures that the parent node is available in the nestedItemMap when building the children.
Here we have the trees, but without the count properties:
let roots: NestedItem[] = Object.keys(nestedItemMap)
.map((key: string): NestedItem => nestedItemMap[key])
.filter((item: NestedItem): boolean => item.root);
To have the count properties filled, I would personally prefer performing a post-order depth-first search on the trees. But in your case, thanks to the node id namings (sorted, the parents nodes ids come first). You can compute them using:
let roots: NestedItem[] = Object.keys(nestedItemMap)
.map((key: string): NestedItem => nestedItemMap[key])
.reverse()
.map((item: NestedItem): NestedItem => {
if(item.children != undefined){
item.count = item.children
.map((child: NestedItem): number => {
return 1 + (child.count != undefined ? child.count : 0);
})
.reduce((a, b) => a + b, 0);
}
return item;
})
.filter((item: NestedItem): boolean => item.root)
.reverse();
I just reverse the array to get all children first (like in a post-order DFS), and compute the count value.
The last reverse is here just to be sorted like in your question :).
maybe this can help you, input is flat obj
nestData = (data, parentId = '') => {
return data.reduce((result, fromData) => {
const obj = Object.assign({}, fromData);
if (parentId === fromData.parent_id) {
const children = this.nestData(data, fromData.id);
if (children.length) {
obj.children = children;
} else {
obj.userData = [];
}
result.push(obj);
}
return result;
}, []);
};
If you have this much information in advance, you can build the tree backwards a lot easier. Since you know the shape of the input so well and their relationships are clearly defined you can easily separate this into multiple arrays and build this from the bottom up:
function buildTree(arr: Item[]): NestedItem[] {
/* first split the input into separate arrays based on their nested level */
const roots = arr.filter(r => /^\w{1}$/.test(r.id));
const levelOne = arr.filter(r => /^\w{1}\d{1}$/.test(r.id));
const levelTwo = arr.filter(r => /^\w{1}\d{1}-\d{1}$/.test(r.id));
/* then create the bottom most level based on their relationship to their parent*/
const nested = levelOne.map(item => {
const children = levelTwo.filter(c => c.parentId === item.id);
if (children) {
return {
...item,
count: children.length,
children
};
} else return item;
});
/* and finally do the same with the root items and return the result */
return roots.map(item => {
const children = nested.filter(c => c.parentId === item.id);
if (children) {
return {
...item,
count: children.length,
children,
root: true
};
} else return { ...item, root: true };
});
}
This might not be the most performant solution, and it would need some tweaking depending on the expected shape of the input, but it is a clean and readable solution.
Another approach might look like this:
const countKids = (nodes) =>
nodes.length + nodes.map(({children = []}) => countKids(children)).reduce((a, b) => a + b, 0)
const makeForest = (id, xs) =>
xs .filter (({parentId}) => parentId == id)
.map (({id, parentId, ...rest}) => {
const kids = makeForest (id, xs)
return {id, ...rest, ...(kids .length ? {count: countKids (kids), children: kids} : {})}
})
const nest = (flat) =>
makeForest (null, flat)
.map ((node) => ({...node, root: true}))
const flat = [{id: "a", name: "Root 1", parentId: null}, {id: "b", name: "Root 2", parentId: null}, {id: "c", name: "Root 3", parentId: null}, {id: "a1", name: "Item 1", parentId: "a"}, {id: "a2", name: "Item 1", parentId: "a"}, {id: "b1", name: "Item 1", parentId: "b"}, {id: "b2", name: "Item 2", parentId: "b"}, {id: "b2-1", name: "Item 2-1", parentId: "b2"}, {id: "b2-2", name: "Item 2-2", parentId: "b2"}, {id: "b3", name: "Item 3", parentId: "b"}, {id: "c1", name: "Item 1", parentId: "c"}, {id: "c2", name: "Item 2", parentId: "c"}]
console .log (nest (flat))
.as-console-wrapper {min-height: 100% !important; top: 0}
The main function (makeForest) finds all the children whose ids match the target (initially null) and then recursively does the same with those children's ids.
The only complexity here is in not including count or children if the children for a node is empty. If including them is not a problem, then this can be simplified.
this.treeData = this.buildTreeData(
flat.filter(f => !f.parentId), flat
);
private buildTreeData(datagroup: Item[], flat: Item[]): any[] {
return datagroup.map((data) => {
const items = this.buildTreeData(
flat.filter((f) => f.parentId === data.id), flat
);
return {
...data,
root: !data.parentId,
count: items?.length || null
children: items,
};
});
}
Hi i tried the accepted answer by Cody and ran into some problems when data wasn't sorted and for nested data with level>2
in this sandbox:
https://codesandbox.io/s/runtime-dew-g48sk?file=/src/index.js:1875-1890
i just changed the order a bit (id=3 was moved to the end of the list), see how in the console we now get that c has only 1 child
I had another problem where parents couldn't be found, because in findParent function the found var was reseted to false if the function was called recursivly with a first argument being an array longer than 1 (e.g. finding a parent for id=21 in:
{id: 1,parentId: null, children: [
{
id: 10,
parentId: 1,
children: []
},
{
id: 11,
parentId: 1,
children: [{
id: 21...
}]
}
]}
would fail
anyway i think the flow itself was good just needed some minor fixes and renames, so here is what's worked for me, I removed some properties that I didn't use (like counter) and added some of my own (like expanded) but it obviously shouldn't matter at all, also im using TS (but i changed all my types to any):
class NestService {
public nestSearchResultsToTree(flatItemsPath: any[]) {
const nested = flatItemsPath.reduce(
(
initial: { nested: any[]; left: any[] },
value: any,
index: number,
original: any
) => {
if (value.parentId === null) {
if (initial.left.length) this.checkLeftOvers(initial.left, value);
initial.nested.push(value);
} else {
const parentFound = this.findParent(initial.nested, value);
if (parentFound) this.checkLeftOvers(initial.left, value);
else initial.left.push(value);
}
return index < original.length - 1 ? initial : initial.nested;
},
{ nested: [], left: [] }
);
return nested;
}
private checkLeftOvers(leftOvers: any[], possibleParent: any) {
for (let i = 0; i < leftOvers.length; i++) {
const possibleChild = leftOvers[i];
if (possibleChild.id === possibleParent.id) continue;
if (possibleChild.parentId === possibleParent.id) {
possibleParent.children
? possibleParent.children.push(possibleChild)
: (possibleParent.children = [possibleChild]);
possibleParent.expanded = true;
possibleParent.isFetched = true;
this.checkLeftOvers(leftOvers, possibleChild);
}
}
}
private findParent(
possibleParents: any,
child: any,
isAlreadyFound?: boolean
): boolean {
if (isAlreadyFound) return true;
let found = false;
for (let i = 0; i < possibleParents.length; i++) {
const possibleParent = possibleParents[i];
if (possibleParent.id === child.parentId) {
possibleParent.expanded = true;
possibleParent.isFetched = true;
found = true;
if (possibleParent.children) possibleParent.children.push(child);
else possibleParent.children = [child];
return true;
} else if (possibleParent.children)
found = this.findParent(possibleParent.children, child, found);
}
return found;
}
}
I got the following array:
var arr = [
{
1: {
id: 1,
title: 'test'
},
children: [
{
1: {
id: 2,
title: 'test2'
}
}
]
}
];
The objects directly in the array are the groups. The 1: is the first language, 2: is second etc. The id is stored in every language object (due to the database I'm using). The children array is built the same way as the 'arr' array.
Example of multiple children:
var arr = [
{
1: {
id: 1,
title: 'test'
},
children: [
{
1: {
id: 2,
title: 'test2'
},
children: [
{
1: {
id: 3,
title: 'test3',
},
children: []
}
]
}
]
}
];
Now I need to delete items from this array. You can have unlimited children (I mean, children can have children who can have children etc.). I have a function which needs an ID parameter sent. My idea is to get the right object where the ID of language 1 is the id parameter. I got this:
function deleteFromArray(id)
{
var recursiveFunction = function (array)
{
for (var i = 0; i < array.length; i++)
{
var item = array[i];
if (item && Number(item[1].ID) === id)
{
delete item;
}
else if (item && Number(item[1].ID) !== id)
{
recursiveFunction(item.children);
}
}
};
recursiveFunction(arr);
}
However, I'm deleting the local variable item except for the item in the array. I don't know how I would fix this problem. I've been looking all over the internet but haven't found anything.
This proposal features a function for recursive call and Array.prototype.some() for the iteration and short circuit if the id is found. Then the array is with Array.prototype.splice() spliced.
var arr = [{ 1: { id: 1, title: 'test' }, children: [{ 1: { id: 2, title: 'test2' }, children: [{ 1: { id: 3, title: 'test3', }, children: [] }] }] }];
function splice(array, id) {
return array.some(function (a, i) {
if (a['1'].id === id) {
array.splice(i, 1)
return true;
}
if (Array.isArray(a.children)) {
return splice(a.children, id);
}
});
}
splice(arr, 2);
document.write('<pre>' + JSON.stringify(arr, 0, 4) + '</pre>');
var arr = [{ 1: { id: 1, title: 'test' }, children: [{ 1: { id: 2, title: 'test2' }, children: [{ 1: { id: 3, title: 'test3', }, children: [] }] }] }];
function deleteFromArray(id) {
function recursiveFunction(arr) {
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
if (item && Number(item[1].id) === id) {
arr.splice(i, 1);
} else if (item && Number(item[1].id) !== id) {
item.children && recursiveFunction(item.children);
}
}
};
recursiveFunction(arr);
};
deleteFromArray(2);
document.getElementById("output").innerHTML = JSON.stringify(arr, 0, 4);
<pre id="output"></pre>
jsfiddle: https://jsfiddle.net/x7mv5h4j/2/
deleteFromArray(2) will make children empty and deleteFromArray(1) will make arr empty itself.