我有一个有孩子的孩子的数组,并且一切都由parentId关联。
示例:
[
{id: 1, parentid:0},{id: 2, parentid:1},
{id: 3, parentid:2},{id: 4, parentid:2},{id: 10, parentid:4},
{id: 5, parentid:0},{id: 6, parentid:5},{id: 7, parentid:7}
]
我想使用Id:1及其所有相关子对象删除该对象。 这样就是这些物体
{id: 1, parentid:0},{id: 2, parentid:1},
{id: 3, parentid:2},{id: 4, parentid:2},{id: 10, parentid:4}
答案 0 :(得分:5)
这是使用递归实现的一种实用方法。编号的项目符号点与下面的代码中的编号注释匹配。
node
,因此无可处理。返回结果r
id
或parentid
在集合s
中,则找到匹配的节点。将节点的id
添加到集合中,并从部分结果r
和其余节点more
开始搜索。more
个节点。
const removeFamily =
( id = 0
, [ node, ...more ] = []
, s = new Set ([ id ])
, r = []
) =>
node === undefined
? r // 1
: s .has (node.id) || s .has (node.parentid)
? removeFamily // 2
( id
, [ ...r, ...more ]
, s .add (node.id)
, []
)
: removeFamily // 3
( id
, more
, s
, [ ...r, node ]
)
const nodes =
[ { id: 1, parentid: 0 }
, { id: 2, parentid: 1 }
, { id: 3, parentid: 2 }
, { id: 4, parentid: 2 }
, { id: 10, parentid: 4 }
, { id: 5, parentid: 0 }
, { id: 6, parentid: 5 }
, { id: 7, parentid: 7 }
]
const newNodes =
removeFamily (1, nodes)
console .log (newNodes)
// [ { id: 5, parentid: 0 }
// , { id: 6, parentid: 5 }
// , { id: 7, parentid: 7 }
// ]
如果可以帮助您更好地查看它,请使用if
语句重写它-
const removeFamily =
( id = 0
, [ node, ...more ] = []
, s = new Set ([ id ])
, r = []
) =>
{ if (node === undefined)
return r // 1
else if (s .has (node.id) || s .has (node.parentid))
return removeFamily // 2
( id
, [ ...r, ...more ]
, s .add (node.id)
, []
)
else
return removeFamily // 3
( id
, more
, s
, [ ...r, node ]
)
}
这是一个使用通用loop
/ recur
接口的堆栈安全变体。即使节点列表可以包含数百万个节点,此版本也可以使用。它还具有稍微更好的公共接口,因为只有两(2)个参数可以在呼叫站点进行配置-
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let a = f ()
while (a && a.recur === recur)
a = f (...a.values)
return a
}
const removeFamily = (id = 0, nodes = []) =>
loop
( ( [ node, ...more ] = nodes
, s = new Set ([ id ])
, r = []
) =>
node === undefined
? r // 1
: s .has (node.id) || s .has (node.parentid)
? recur // 2
( [ ...r, ...more ]
, s .add (node.id)
, []
)
: recur // 3
( more
, s
, [ ...r, node ]
)
)
const nodes =
[ { id: 1, parentid: 0 }
, { id: 2, parentid: 1 }
, { id: 3, parentid: 2 }
, { id: 4, parentid: 2 }
, { id: 10, parentid: 4 }
, { id: 5, parentid: 0 }
, { id: 6, parentid: 5 }
, { id: 7, parentid: 7 }
]
const newNodes =
removeFamily (1, nodes)
console .log (newNodes)
// [ { id: 5, parentid: 0 }
// , { id: 6, parentid: 5 }
// , { id: 7, parentid: 7 }
// ]
答案 1 :(得分:2)
对于关系,您可以选择Map
,对于删除的所有id
,可以选择Generator
。
function* remove(id) {
yield id;
for (id of relations.get(id) || []) yield* remove(id);
}
var data = [{ id: 1, parentid: 0 }, { id: 2, parentid: 1 }, { id: 3, parentid: 2 }, { id: 4, parentid: 2 }, { id: 10, parentid: 4 }, { id: 5, parentid: 0 }, { id: 6, parentid: 5 }, { id: 7, parentid: 7 }],
relations = data.reduce((m, { id, parentid }) => m.set(parentid, [...(m.get(parentid) || []), id]), new Map),
id = 1,
ids = [...remove(id)],
i = data.length;
while (i--)
if (ids.includes(data[i].id))
data.splice(i, 1);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 2 :(得分:1)
摘要
您基本上是在修剪家谱。由于没有显式的树数据结构,这项工作变得很复杂。相反,树结构是由一组本地父母关系所暗示的(为您提供这些关系的数组的条目可以按任何顺序排序)。
您可以首先构建一个真正的树结构,然后使用.parentid === 1
删除所有节点(保留您的示例),并消除所有后代。
可以通过不构建其根为.parentid === 1
的子树来优化此过程。
以下建议比较简单。该代码反复搜索已知已消除的节点的子节点,直到不再找到新的此类子节点为止。因此,它可以跟踪字典中当前已知的后代。
这个简单的想法是以最坏情况下的O(n^2)
运行时间为代价的,n
是原始数组中条目的数量。
该算法是尾递归的实例,因此可以将递归示意性地转换为循环。
请注意,[p]bdict_seen
字典实际上可以删除,因为它的更新确实反映了[p]bdict_descendants
字典的更新。
运行代码(对于给定的示例):
'node <thisfile>.js'
代码
let ao_nodes = [
{id: 1, parentid:0},{id: 2, parentid:1},
{id: 3, parentid:2},{id: 4, parentid:2},{id: 10, parentid:4},
{id: 5, parentid:0},{id: 6, parentid:5},{id: 7, parentid:7}
];
function demo_kernel ( pbdict_descendants, pbdict_seen ) {
let b_foundsome = false
;
//
// For all nodes:
// If not yet identified as a descendant and its parent is among the set of known ancestors, add it to the set of descendants.
//
for (let o_node of ao_nodes ) {
if (!pbdict_seen.hasOwnProperty ( o_node.id )) { // using 'pbdict_descendants' for this test is equivalent; in doing so, [p]bdict_seen can be removed from the code altogether.
if (pbdict_descendants.hasOwnProperty ( o_node.parentid )) {
b_foundsome = true;
pbdict_descendants[o_node.id] = true;
pbdict_seen[o_node.id] = true;
}
}
}
//
// At least 1 new descendant has been found on this level.
// If no more descendants are found, this marks the end of the recursion.
//
if (b_foundsome) {
demo_kernel ( pbdict_descendants, pbdict_seen );
}
} // demo_kernel
function demo_kernel_nonrec ( pbdict_descendants, pbdict_seen ) {
let b_foundsome = true
;
//
// For all nodes:
// If not yet identified as a descendant and its parent is among the set of known ancestors, add it to the set of descendants.
//
while (b_foundsome) {
b_foundsome = false;
for (let o_node of ao_nodes ) {
if (!pbdict_seen.hasOwnProperty ( o_node.id )) { // using 'pbdict_descendants' for this test is equivalent; in doing so, [p]bdict_seen can be removed from the code altogether.
if (pbdict_descendants.hasOwnProperty ( o_node.parentid )) {
b_foundsome = true;
pbdict_descendants[o_node.id] = true;
pbdict_seen[o_node.id] = true;
}
}
}
}
} // demo_kernel_nonrec
function demo ( ps_id ) {
let ao_purged
, bdict_descendants
, bdict_seen
;
//
// Register start node
//
bdict_descendants = {
[ps_id]: true
};
bdict_seen = {
[ps_id]: true
};
//
// identify descendants.
// Express recursion recursion
//
// Use either one of the next two lines
// demo_kernel: recursive (demonstration purpose only)
// demo_kernel_nonrec: non-recursive (use this one)
//
//*** demo_kernel ( bdict_descendants, bdict_seen );
demo_kernel_nonrec ( bdict_descendants, bdict_seen );
//
// Compile result: produce the purged set of nodes.
//
ao_purged = [];
for (let o_node of ao_nodes ) {
if (!bdict_descendants.hasOwnProperty ( o_node.id )) {
ao_purged.push ( o_node );
}
}
return ao_purged;
}
let n_root = 1
;
console.log ( `original:\n${JSON.stringify(ao_nodes)}.\n\n` );
console.log ( `purged (root: ${n_root}):\n${JSON.stringify(demo ( n_root ))}.\n` ); // Prints to the browser console.
答案 3 :(得分:0)
使用ES6进行递归深度
没有测试,但是会是这样
var dataStore = [{}] // filled in with your data
function removeDataWithRelationships(id) {
// find root parent to remove
var itemToRemoveIndex = dataStore.findIndex(ds => ds.id === id);
// grab reference to remove
var currentReference = dataStore[itemToRemoveIndex]
// remove current item
dataStore.splice(itemToRemoveIndex,1);
// look for children on currentReference
var childrenToRemove = dataStore.find(ds => ds.parentid === currentReference.id);
// if there are children, look for parents and run recursive operation
if (childrenToRemove) {
//recursively call this function to remove all children
childrenToRemove.forEach(id => {
removeDataWithRelationship(id);
});
}
}
答案 4 :(得分:0)
您想要的是深度优先(或广度优先)搜索。因此,您可以使用DFS查找所有子节点和子节点,然后在找到所有子节点和子节点后将其过滤掉。
function removeFromID(id) {
let stack = [], found = [];
children.forEach(child => {
if (child.id === id) {
found.push(child);
stack.push(child);
});
while (stack.length > 0) {
let current = stack.pop();
children.forEach(child => {
if (child.id === current.id) {
stack.push(child);
found.push(child);
}
});
}
children = children.filter(child => found.indexOf(child) <= -1);
}
答案 5 :(得分:0)
此解决方案不依赖于起始数组的排序顺序。也就是说,可以在数组的开头找到孙子代。
代码中有解释(将数组改写为在前面有granchildren):
// this array is rewritten so granchildren appear first!
let arr = [
{id: 3, parentid:2},{id: 4, parentid:2},{id: 10, parentid:4},
{id: 5, parentid:0},{id: 6, parentid:5},{id: 7, parentid:7},
{id: 1, parentid:0},{id: 2, parentid:1}
]
function remove(id, arr) {
//first time it's called id is put into an array
let del = (Array.isArray(id))? id: [id]
let newArr = []
arr.forEach((obj) => {
switch (true) {
// removes topmost parent
case del.includes(obj.id):
break;
// removes subsequent children
case del.includes(obj.parentid):
del.push(obj.id)
break;
// retains the rest
default:
newArr.push(obj)
}
})
// if this pass did remove something, we call function again
// since original array may not be sorted and deep grandchildren
// are found in the beginning of the array
if (arr.length !== newArr.length) {newArr = remove(del, newArr)}
// when no further changes are made, we return the result
return newArr
}
console.log(remove(1, arr)) //results in [{id:5,parentid:0}, {id:6,parentid:5},{id:7,parentid:7}