Javascript – How to remove all items with a particular ID and its associated items? Then its associated items and its subsequent items (recursion?)

huangapple go评论53阅读模式
英文:

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 =&gt; [o.parentId, o]))
let remove = [1]

while (remove.length &gt; 0) {
    let id = remove.shift()
    let obj = m.get(id)
    if (obj) {
        console.log(&#39;debug: deleting&#39;, id)
        m.delete(id)

        remove.push(...obj.children.map(c =&gt; 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 &#39;ramda&#39;

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) =&gt; R.pipe(
  R.find(R.propEq(&quot;parentId&quot;,id)),            // find parent
  R.propOr([],&quot;children&quot;),                    // handle zero case  
  R.pluck(&quot;childId&quot;),                         // find the children  
  R.reduce(R.flip(removeDesc), arr),          // recurse the children
  R.reject(R.propEq(&quot;parentId&quot;, id))          // then remove the parent
)(arr)

console.log( JSON.stringify( removeDesc(1,initialArr) ) )   
// [{&quot;parentId&quot;:7,&quot;children&quot;:[{&quot;childId&quot;:711},{&quot;childId&quot;:721},{&quot;childId&quot;: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 &amp;&amp; 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(&#39;output&#39;).innerHTML = JSON.stringify(newArr, null, 2);

<!-- language: lang-html -->

&lt;pre id=&quot;output&quot;&gt;&lt;/pre&gt;

<!-- 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) =&gt; {
  const parent = _.find(arr, { parentId });
  if (!parent) return arr;
  
  let updatedArr = _.reject(arr, { parentId });
  parent.children.forEach(child =&gt; {
    updatedArr = removeByParentId(updatedArr, child.childId);
  });

  return updatedArr;
};

const outputArr = removeByParentId(arr, 1);

console.log(outputArr);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年3月31日 18:33:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/75897525.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定