【问题标题】:How can I use Lodash/JS to recursively filter nested objects?如何使用 Lodash/JS 递归过滤嵌套对象?
【发布时间】:2019-02-11 19:05:53
【问题描述】:

我有一个包含未知深度对象的数组,像这样

var objects = [{
    id: 1,
    name: 'foo'
}, {
    id: 2,
    name: 'bar',
    childs: [{
        id: 3,
        name: 'baz',
        childs: [{
            id: 4,
            name: 'foobar'
        }]
    }]
}];

我希望能够通过它的 id 过滤特定的子对象。

目前我正在使用这个小 lodash 脚本(引用自 this question),但它仅适用于不超过一层的对象。因此,搜索 id: 1id: 2 可以正常工作,而搜索 id: 3id: 4 将返回 undefined。

function deepFilter(obj, search) {
    return _(obj)
        .thru(function(coll) {
            return _.union(coll, _.map(coll, 'children'));
        })
        .flatten()
        .find(search);
}

A little JSfiddle.

【问题讨论】:

  • 你想得到带有质疑id的对象吗?
  • 是的,这正是我想要实现的目标

标签: javascript recursion multidimensional-array filter lodash


【解决方案1】:

你可以有一个递归函数并检查孩子

var objects = [{
  id: 1,
  name: 'foo'
}, {
  id: 2,
  name: 'bar',
  childs: [{
    id: 3,
    name: 'baz',
    childs: [{
      id: 4,
      name: 'foobar'
    }]
  }]
}];
let tempArray = [];


function doRecursiveSearch(obj, id) {

  obj.forEach(function(item) {
    console.log(item)
    if (item.id === id) {
      tempArray.push(item)
    } else {
      if (item.childs && Array.isArray(item.childs)) {
        console.log(item)
        doRecursiveSearch(item.childs, id)
      }
    }

  })
}
doRecursiveSearch(objects, 4)
console.log(tempArray)

【讨论】:

    【解决方案2】:

    您需要递归调用该函数才能定位子对象。尝试关注

    遍历数组并为每个对象检查是否找到id。如果是,则中断并返回结果,否则继续在child(如果存在)中搜索。

    方法一:逐个分支遍历树枝

    使用这种方法,代码首先遍历第一个元素直到最后一个子元素,然后是第二个元素这个最后一个子元素,依此类推。

    var objects = [{id: 1,name: 'foo'}, {id: 2,name: 'bar',childs: [{id: 3,name: 'baz',childs: [{id: 4,name: 'foobar'}]}]}];
    
    function findObject(arr, id) {
      var result;
      for (let i = 0 ; i < arr.length; i++) {
        if(arr[i].id === id) {
          result = arr[i];
          break;
        }
        if(arr[i].childs) {
          result = findObject(arr[i].childs, id);
          if(result) break;
        }
      }
      return result;
    }
    
    console.log(findObject(objects, 4));

    方法2:按深度遍历树的深度

    使用这种方法,代码首先遍历第一级元素,然后是第二级元素,依此类推。

    var objects = [{id: 1,name: 'foo'}, {id: 2,name: 'bar',childs: [{id: 3,name: 'baz',childs: [{id: 4,name: 'foobar'}]}]}];
    
    function findObject(arr, id) {
      var result;
      var children = [];
      for (let i = 0 ; i < arr.length; i++) {
        if(arr[i].id === id) {
          result = arr[i];
          break;
        }
        if(arr[i].childs) {
          children = [...children, ...arr[i].childs];
        }
      }
      if(!result && children.length) {
        result = findObject(children, id);
      }
      return result;
    }
    
    console.log(findObject(objects, 4));

    【讨论】:

      【解决方案3】:

      您可以采用迭代和递归的方法。

      function find(id, array) {
          var result;
          array.some(o => o.id === id && (result = o) || (result = find(id, o.children || [])));
          return result;
      }
      
      var objects = [{ id: 1, name: 'foo' }, { id: 2, name: 'bar', children: [{ id: 3, name: 'baz', children: [{ id: 4, name: 'foobar' }] }] }];
      
      console.log(find(1, objects));
      console.log(find(2, objects));
      console.log(find(3, objects));
      console.log(find(4, objects));
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      【讨论】:

        【解决方案4】:

        您可以像这样递归地执行此操作:

        function deepFind(arr, search) {
            for(var obj of arr) {
                if(search(obj)) {
                    return obj;
                }
                if(obj.childs) {
                    var deepResult = deepFind(obj.childs, search);
                    if(deepResult) {
                        return deepResult;
                    }
                }
            }
            return null;
        }
        

        然后像这样使用它:

        var result = deepFind(objects, function(obj) {
            return obj.id === myId;
        });
        

        示例:

        function deepFind(arr, search) {
            for(var obj of arr) {
                if(search(obj)) {
                    return obj;
                }
                if(obj.childs) {
                    var deepResult = deepFind(obj.childs, search);
                    if(deepResult) {
                        return deepResult;
                    }
                }
            }
            return null;
        }
        
        var objects = [{id: 1,name: 'foo'}, {id: 2,name: 'bar',childs: [{id: 3,name: 'baz',childs: [{id: 4,name: 'foobar'}]}]}];
        
        console.log("ID 1:", deepFind(objects, obj => obj.id === 1));
        console.log("ID 4:", deepFind(objects, obj => obj.id === 4));
        console.log("ID 7:", deepFind(objects, obj => obj.id === 7));

        【讨论】:

        • 我最喜欢这个解决方案,因为我没有绑定到您的函数中的对象属性。谢谢易卜拉欣!
        • 不客气!这是我最接近 lodash 的 find 灵活性
        猜你喜欢
        • 1970-01-01
        • 2013-06-10
        • 2016-03-23
        • 1970-01-01
        • 2019-09-15
        • 1970-01-01
        • 2017-02-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多