我不知道怎么做才好。
在下面的示例:
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,那么它们的后续子元素也是。因此,parentid为11,21,31。31是一个parentId,所以删除它的子id - 111、211和311。311是一个parentId,所以删除它的子id。311中没有childds作为parentIds,所以我们就到此为止。
如果有人能建议最好的方法去做。我在考虑递归,但我看到的例子更多的是嵌套数组,而不是子数组,然后分离数组并重复这个过程。
就剩下
了[{
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。为方便起见,我们还将数组转换为map 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>