【问题标题】:Recursively find item in array and splice out found item from the reference array递归查找数组中的项并从参考数组中拼接出找到的项
【发布时间】:2020-03-21 09:33:54
【问题描述】:

我正在尝试以递归方式在对象数组中查找项,然后重建相同的数组,但其中没有找到的项。找到该项目后,我想将其从参考数组中拼接出来。以下是我的尝试,但不幸的是它根本不起作用。

var tt = [{ age : 4, els : [{ age : 12, els : [] },{ age : 32, els : [{ age :44, els :[] },{ age : 100, els : [ { age: 3, els : [], age : 22, els : [{ age : 13, els : []},{ age : 99, els : []},{ age : 88, els : [{ age : 16, els : [] }]}] } ] }] }] },{ age: 223, els : [] },{ age : 120, els : [{ age :300, els : [] },{ age :301, els : [{ age : 400, els : [] }] }] }];

kk = [];

var test = function(els){
 for( var i = 0; i < els.length; i++ ){
   if( els[i].age == 400 ){
     console.log('found');
     console.log(els[i]);
     return;
   }else{
    kk.push(els[i]);
    test(els[i].els);
   }
 }
}

console.log( tt ) // -- show original array
console.log( test(tt) ); // -- show found item
console.log( kk ); // -- show new array without the newly found item

【问题讨论】:

  • 让函数改变一个硬编码的kk 不是一个好主意——如果你想让函数检索匹配的元素并产生一个过滤的版本,我的建议是返回一对值一个东西。我建议修改您的设计或explaining why you need to follow such an unusual requirement。除此之外,当删除与谓词匹配的元素时,子元素会发生什么?多个元素匹配谓词时应该怎么做?
  • 另外,当你说“拼接”时,这表明你想要改变原件。这是意图还是您想要一个全新的副本?如果您正在变异,返回副本似乎没有任何好处,因此要求似乎有点矛盾。感谢您的澄清!
  • @ggorlen 我的目标只是找到一个项目并将其从数组中删除。
  • 好的,明白了。谢谢。

标签: javascript arrays recursion tree javascript-objects


【解决方案1】:

虽然目标很崇高,但我认为提议的设计不是一个合理的选择。这里有一些违规行为:

  • Encapsulation 坏了。通过 hardcoding test 仅使用特定名称 kk 填充全局,我们不必要地将函数绑定到单个上下文,使其无法重用。
  • 通过返回一个值并生成一个side effecttest 函数变得难以推理。
  • 没有理由不做子键和目标移除值参数,所以泛化test(我们称之为函数filterRecursive)。与Array#filter 一样,此函数应与任意回调谓词一起使用。
  • 这些变量名称不是非常具有描述性的选择,但我假设这只是为了解决问题。

以下是有关如何处理此问题的建议。我正在返回一个包含 resultremoved 键的对象(我对 returning two values 并不感兴趣,但它比副作用好),它允许您访问更新的结构以及扁平列表所有已删除的未通过谓词的对象。原始数组未发生突变。

const data = [
  {
    age: 1,
    els: [{
      age: 2,
      els: []
    }, {
      age: 3,
      els: [{
        age: 4,
        els: []
      }, {
        age: 5,
        els: []
      }]
    }]
  },
  {
    age: 6,
    els: []
  }
];


const filterRecursive = (arr, predicate, childKey, removed=[]) => {
  removed.push(...arr.filter(e => !predicate(e)));  
  const result = arr.filter(predicate).map(e => {
    if (e[childKey]) {
      const {result: sub} = filterRecursive(e[childKey], predicate, childKey, removed);
      return {...e, [childKey]: sub};
    }
    
    return e;
  });

  return {result: result, removed: removed};
};

const {result, removed} = filterRecursive(data, e => ![4, 6].includes(e.age), "els");
console.log("original", data);
console.log("result", result);
console.log("removed", removed);

这是对原始结构和谓词的运行:

const filterRecursive = (arr, predicate, childKey, removed=[]) => {
  removed.push(...arr.filter(e => !predicate(e)));  
  const result = arr.filter(predicate).map(e => {
    if (e[childKey]) {
      const {result: sub} = filterRecursive(e[childKey], predicate, childKey, removed);
      return {...e, [childKey]: sub};
    }

    return e;
  });

  return {result: result, removed: removed};
};

const data = [{ age : 4, els : [{ age : 12, els : [] },{ age : 32, els : [{ age :44, els :[] },{ age : 100, els : [ { age: 3, els : [], age : 22, els : [{ age : 13, els : []},{ age : 99, els : []},{ age : 88, els : [{ age : 16, els : [] }]}] } ] }] }] },{ age: 223, els : [] },{ age : 120, els : [{ age :300, els : [] },{ age :301, els : [{ age : 400, els : [] }] }] }];
console.log(filterRecursive(data, e => e.age !== 400, "els"));
console.log(data);

【讨论】:

    【解决方案2】:

    因为在您的 test() 中的 for 循环中,有一个返回,这将打破循环但不返回任何内容。你应该 return 退出 for 循环

    因为你有一个递归调用test(),所以最好定义另一个数组来保存你找到的项目,然后console.log

    var tt = [{ age : 4, els : [{ age : 12, els : [] },{ age : 32, els : [{ age :44, els :[] },{ age : 100, els : [ { age: 3, els : [], age : 22, els : [{ age : 13, els : []},{ age : 99, els : []},{ age : 88, els : [{ age : 16, els : [] }]}] } ] }] }] },{ age: 223, els : [] },{ age : 120, els : [{ age :300, els : [] },{ age :301, els : [{ age : 400, els : [] }] }] }];
    
    var kk = [];
    var mm = [];
    
    var test = function(els){
     for( var i = 0; i < els.length; i++ ){
       if( els[i].age == 400 ){
         console.log('found');
         console.log(els[i]);
         mm.push(els[i])
       }else{
        kk.push(els[i]);
        test(els[i].els);
       }
     }
     // return at here, not in the for-loop
     return mm;
    }
    
    console.log( tt ) // -- show original array
    console.log( test(tt), mm ); // -- show found item
    console.log( kk ); // -- show new array without the newly found item

    【讨论】:

      【解决方案3】:

      这是一个有趣的例子。 下面是我的代码。

      var tt = [{ age: 4, els: [{ age: 12, els: [] }, { age: 400, els: [{ age: 44, els: [] }, { age: 100, els: [{ age: 3, els: [], age: 22, els: [{ age: 13, els: [] }, { age: 99, els: [] }, { age: 88, els: [{ age: 16, els: [] }] }] }] }] }] }, { age: 223, els: [] }, { age: 120, els: [{ age: 300, els: [] }, { age: 301, els: [{ age: 400, els: [] }] }] }];
      
      
      
      var test = function(els) {
        const newEls = []
        for (var i = 0; i < els.length; i++) {
          if (els[i].age == 400) {
            console.log('found');
            console.log(els[i]);
          } else {
            newEls.push({
              age: els[i].age,
              els: test(els[i].els)
            })
          }
        }
        return newEls
      }
      
      console.log(tt) // -- show original array
      const kk = test(tt); // -- show found item
      console.log(kk); // -- show new array without the newly found item
      

      【讨论】:

        【解决方案4】:

        我会为此使用递归减少。在您的迭代过程中,您会跳过 .age === 400 的所有项目,然后在返回之前对 .els 执行相同的过程:

        const remove = xs =>
          xs.reduce((ret, {age, els}) =>
            age === 400
              ? ret
              : ret.concat({age, els: remove(els)}),
            []);
        
        
        console.log(
        
          remove(data)
          
        );
        <script>
        const data = [
          {age: 4, els: [
            {age: 12, els: []},
            {age: 32, els: [
              {age: 44, els: []},
              {age: 100, els: [
                {age: 3, els: []},
                {age: 22, els: [
                  {age: 13, els: []},
                  {age: 99, els: []},
                  {age: 88, els: [
                    {age: 16, els: []}]}]}]}]}]},
          {age: 223, els: []},
          {age: 120, els: [
            {age: 300, els: []},
            {age: 301, els: [
              {age: 400, els: []}]}]}];
        </script>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-17
          • 1970-01-01
          • 2019-11-14
          • 1970-01-01
          • 2017-06-10
          • 2016-06-23
          相关资源
          最近更新 更多