Javascript - 如何删除具有特定 ID 的所有项目及其关联项目?然后是它的关联项及其后续项(递归?)

问题描述 投票:0回答:5

我在解决这个问题的最佳方法上遇到了一些困难。

下面的例子:

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 },
  ]
}]
javascript arrays recursion
5个回答
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; }


1
投票

一种可能性是有一个要删除的 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)


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}]}]

我发现使用像这样的函数式编程风格可以使代码更易于理解(从长远来看!)。它也倾向于鼓励使用不可变的数据结构,因此通过修改产生意外后果的风险较小。不过,它在运行时不一定是最有效的。


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>


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>

© www.soinside.com 2019 - 2024. All rights reserved.