通过删除尾部匹配的节点递归地过滤对象

时间:2017-04-10 12:26:41

标签: javascript algorithm

我在使用对象中的父项过滤所有匹配节点时遇到了常见问题。如果我们在叶子中匹配,那将非常容易。问题在于嵌套不匹配的分支。目前,当我面对任何一个孩子的节点时,其中一个节点可能会匹配,所以我需要将此父节点添加为潜在匹配。 当我降低几个级别并且没有得到匹配时,访问了“可能的”节点,我需要再次通过整个树来找到那些(几次)。 我有一个丑陋的解决方案:首先得到树级别并在for循环中重复过滤,以便不添加那些没有子节点的节点。这很糟糕,因为不准确。

我想调用过滤一次以获得结果。

在下面的代码中,经过5次“清理”迭代后,它最终会返回正确的结果。

预期结果:

[{
    "content": { "name": "match" },
    "children": []
}]

脚本:

const items = [{
    content: { name: "match" },
    children: [{
        content: { name: "miss 1" },
        children: [{
            content: { name: "miss 2" },
            children: [{
                content: { name: "node 1" },
                children: []
            }, {
                content: { name: "node 2" },
                children: [{
                content: { name: "node 2" },
                children: []
                }, {
                    content: { name: "node 22" },
                    children: [{
                    content: { name: "node 23" },
                    children: []
                    }]
                }, {
                    content: { name: "node 23" },
                    children: []
                }]
            }, {
                content: { name: "node 3" },
                children: []
            }]
        }]
    }]
}, {
    content: { name: "Root 2" },
    children: []
}];

searchText = "match";

function filterItems(items, searchText) {
    var filtredItems = [];

    items.forEach(
        item => {
            if (item.children.length > 0 || item.content.name.includes(searchText)) {
                item.children = filterItems(item.children, searchText);
                filtredItems.push(item);
            }
        } 
    )
    return filtredItems;
}

console.log(JSON.stringify(filterItems(items, searchText), null, 2));
console.log(JSON.stringify(filterItems(items, searchText), null, 2));
console.log(JSON.stringify(filterItems(items, searchText), null, 2));
console.log(JSON.stringify(filterItems(items, searchText), null, 2));
console.log(JSON.stringify(filterItems(items, searchText), null, 2)); // finally get result here

好的,所以这假设是树视图中的搜索功能。搜索一些名称我需要获得与所有父母匹配的节点,直到根和没有任何其他分支,也没有孩子的一旦任何不匹配。用例示例:

tree = 
[aa
    bb
    cc
        dd
            ff
            gg
        hh
        cc      
]       

search for:
aa =>
[aa]

dd =>
[aa
    cc
        dd
]

cc =>
[aa
    cc
        cc
]

2 个答案:

答案 0 :(得分:0)

如果想要过滤节点,我会首先以递归方式展平树,然后过滤生成的数组:

function recFlatten (list, item) {
  list.push(item)
  if (item.hasOwnProperty('children')) {
    for (var i in item.children) {
      if (item.children.hasOwnProperty(i)) {
        recFlatten(list, item.children[i])
      }
    }
  }
  return list
}
var flatList = recFlatten([], items[0]})
var results = flatList.filter(item => ...)

答案 1 :(得分:0)

您可以为子项使用递归方法,如果某些名称匹配或某些子项匹配,则创建一个具有content属性的新对象和匹配的子项。



function getNodes(array, name) {
    return array.reduce(function (r, a) {
        var temp = getNodes(a.children, name);
        return r.concat(
            a.content.name.includes(name) || temp.length ?
            Object.assign({}, a, { children: temp }) :
            []
        );
    }, []);
}

var items = [{ content: { name: "match" }, children: [{ content: { name: "miss 1" }, children: [{ content: { name: "miss 2" }, children: [{ content: { name: "node 1" }, children: [] }, { content: { name: "node 2" }, children: [{ content: { name: "node 2" }, children: [] }, { content: { name: "node 22" }, children: [{ content: { name: "node 23" }, children: [] }] }, { content: { name: "node 23" }, children: [] }] }, { content: { name: "node 3" }, children: [] }] }] }] }, { content: { name: "Root 2" }, children: [] }];

console.log(getNodes(items, 'match'));
console.log(getNodes(items, 'miss 1'));
console.log(getNodes(items, 'node 1'));
console.log(getNodes(items, 'node 2'));

.as-console-wrapper { max-height: 100% !important; top: 0; }