我在解决这个问题的最佳方法上遇到了一些困难。
下面的例子:
const arr = [{
parentId: 1,
children: [
{ childId: 11 },
{ childId: 21 },
{ childId: 31 },
]
}, {
parentId: 31,
children: [
{ childId: 111 },
{ childId: 211 },
{ childId: 311 },
]
}, {
parentId: 7,
children: [
{ childId: 711 },
{ childId: 721 },
{ childId: 731 },
]
}, {
parentId: 311,
children: [
{ childId: 3111 },
{ childId: 3211 },
{ childId: 3311 },
]
}]
所以,假设我想删除 parentId = 1 那么我想删除所有它的关联子项,如果关联的子项也是 parentId 那么他们的后续子项也是如此。因此,parentIds 11、21、31。31 是一个 parentId,因此删除其 childIds - 111、211 和 311。311 是一个 parentId,因此删除其 childId。没有 childIds 作为 parentIds fr 311 所以我们可以到此为止。
如果有人能够建议最好的方法,请。我在考虑递归,但我看到的例子更多的是嵌套数组而不是子数组,然后分离数组并重复这个过程。
所以我们会留下
[{
parentId: 7,
children: [
{ childId: 711 },
{ childId: 721 },
{ childId: 731 },
]
}]
Set
上使用闭包进行过滤,其中收集了所有childId
。
const
remove = (data, id) => data.filter((s => o => {
if (!s.has(o.parentId)) return true;
o.children.forEach(({ childId }) => s.add(childId));
})(new Set([id]))),
data = [{ parentId: 1, children: [{ childId: 11 }, { childId: 21 }, { childId: 31 }] }, { parentId: 31, children: [{ childId: 111 }, { childId: 211 }, { childId: 311 }] }, { parentId: 7, children: [{ childId: 711 }, { childId: 721 }, { childId: 731 }] }, { parentId: 311, children: [{ childId: 3111 }, { childId: 3211 }, { childId: 3311 }] }],
result = remove(data, 1);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
一种可能性是有一个要删除的 id 队列,删除队列顶部的一个 id 并附加所有依赖的 id。为了方便起见,我们也将您的数组转换为地图 id->object:
const arr=[{parentId:1,children:[{childId:11},{childId:21},{childId:31}]},{parentId:31,children:[{childId:111},{childId:211},{childId:311}]},{parentId:7,children:[{childId:711},{childId:721},{childId:731}]},{parentId:311,children:[{childId:3111},{childId:3211},{childId:3311}]}]
//
let m = new Map(arr.map(o => [o.parentId, o]))
let remove = [1]
while (remove.length > 0) {
let id = remove.shift()
let obj = m.get(id)
if (obj) {
console.log('debug: deleting', id)
m.delete(id)
remove.push(...obj.children.map(c => c.childId))
}
}
let result = [...m.values()]
console.log(result)
使用递归和 Ramda.js 库的可能性:
import * as R from 'ramda'
const initialArr = [
{ parentId: 1, children: [{ childId: 11 }, { childId: 21 }, { childId: 31 }] },
{ parentId: 31, children: [{ childId: 111 }, { childId: 211 }, { childId: 311 }] },
{ parentId: 7, children: [{ childId: 711 }, { childId: 721 }, { childId: 731 }] },
{ parentId: 311, children: [{ childId: 3111 }, { childId: 3211 }, { childId: 3311 }] }
]
const removeDesc = (id,arr) => R.pipe(
R.find(R.propEq("parentId",id)), // find parent
R.propOr([],"children"), // handle zero case
R.pluck("childId"), // find the children
R.reduce(R.flip(removeDesc), arr), // recurse the children
R.reject(R.propEq("parentId", id)) // then remove the parent
)(arr)
console.log( JSON.stringify( removeDesc(1,initialArr) ) )
// [{"parentId":7,"children":[{"childId":711},{"childId":721},{"childId":731}]}]
我发现使用像这样的函数式编程风格可以使代码更易于理解(从长远来看!)。它也倾向于鼓励使用不可变的数据结构,因此通过修改产生意外后果的风险较小。不过,它在运行时不一定是最有效的。
你可以使用递归来解决这个问题。
const arr=[{parentId:1,children:[{childId:11},{childId:21},{childId:31}]},{parentId:31,children:[{childId:111},{childId:211},{childId:311}]},{parentId:7,children:[{childId:711},{childId:721},{childId:731}]},{parentId:311,children:[{childId:3111},{childId:3211},{childId:3311}]}];
function myReduce(inputArr, key) {
for (let [i, arrElem] of inputArr.entries()) {
if (arrElem.parentId && arrElem.parentId === key) {
const childElem = arrElem.children;
if (childElem.length) {
for (let child of childElem) {
myReduce(inputArr, child.childId);
}
}
inputArr.splice(i, 1);
}
}
return inputArr;
}
const newArr = myReduce(arr, 1);
document.getElementById('output').innerHTML = JSON.stringify(newArr, null, 2);
<pre id="output"></pre>
您可以将此方法与
lodash
和递归一起使用:
const arr = [{
parentId: 1,
children: [
{ childId: 11 },
{ childId: 21 },
{ childId: 31 },
]
}, {
parentId: 31,
children: [
{ childId: 111 },
{ childId: 211 },
{ childId: 311 },
]
}, {
parentId: 7,
children: [
{ childId: 711 },
{ childId: 721 },
{ childId: 731 },
]
}, {
parentId: 311,
children: [
{ childId: 3111 },
{ childId: 3211 },
{ childId: 3311 },
]
}]
const removeByParentId = (arr, parentId) => {
const parent = _.find(arr, { parentId });
if (!parent) return arr;
let updatedArr = _.reject(arr, { parentId });
parent.children.forEach(child => {
updatedArr = removeByParentId(updatedArr, child.childId);
});
return updatedArr;
};
const outputArr = removeByParentId(arr, 1);
console.log(outputArr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>