英文:
Javascript - How to remove all items with a particular ID and its associated items? Then its associated items and its subsequent items (recursion?)
问题
以下是翻译好的部分:
"我在如何处理这个问题的最佳方式方面遇到了一些困难。
例如:
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,所以删除它的childIds。对于311,没有childIds作为parentIds,所以我们可以在那里停止。
如果有人能够建议最佳处理方法,请告诉我。我想到了递归,但我看到的示例更多是用于嵌套数组,而不是孩子和单独的数组,然后重复这个过程。
因此,我们将剩下
[{
parentId: 7,
children: [
{ childId: 711 },
{ childId: 721 },
{ childId: 731 },
]
}]"
英文:
I am having some difficulties in what the best way to go about this is.
Example below:
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 },
]
}]
So, say I want to remove parentId = 1 then I would like to remove all its assoicated children and if the associated children also is a parentId then their subsequent children as well. Therefore, parentIds 11, 21, 31. 31 is a parentId so remove its childIds - 111, 211 and 311. 311 is a parentId so remove its childIds. No childIds as parentIds fr 311 so we can stop there.
Please if anyone is able to advise best way to go about it. I was thinking recursion but the examples I have seen is more for nested arrays rather than children then separate arrays and repeat the process.
So we would be left with
[{
parentId: 7,
children: [
{ childId: 711 },
{ childId: 721 },
{ childId: 731 },
]
}]
答案1
得分: 2
你不需要递归,因为数据已经排序并且是扁平的,你可以使用一个针对 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; }
英文:
You need no recursion, because of the sorted and flat data and you could filter with a closure over a Set
where all childId
are collected.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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);
<!-- language: lang-css -->
.as-console-wrapper { max-height: 100% !important; top: 0; }
<!-- end snippet -->
答案2
得分: 1
以下是代码的翻译部分:
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)
希望这对你有所帮助。
英文:
One possibility is to have a queue of ids-to-delete, delete an id on the top of the queue and append all dependent ids. For convenience, let's also convert your array to a map id->object:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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)
<!-- end snippet -->
答案3
得分: 1
以下是使用递归和 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}]}
使用这种函数式编程风格使得代码更容易理解(长期来看)。它还倾向于使用不可变数据结构,因此通过修改数据造成意外后果的风险较小。不过,它在运行时不一定是最高效的。
英文:
A possibility using recursion and the Ramda.js library:
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}]}]
Using a functional-programming style like this I find makes the code easier to follow (in the long-run!). It tends to encourage using immutable data structures too, so there's less risk of unintended consequences through modification. It's not necessarily the most efficient at run-time though.
答案4
得分: 0
你可以使用递归来解决这个问题。
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>
英文:
You can use recursion to solve this.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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);
<!-- language: lang-html -->
<pre id="output"></pre>
<!-- end snippet -->
答案5
得分: 0
您可以使用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>
英文:
You can use this approach with lodash
and recursion:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论