2017-04-10 43 views
1

我在過濾與對象中父對象相匹配的所有節點時存在常見問題。很容易,如果我們得到匹配的葉子。問題是嵌套不匹配分支。目前,當我面對一些有任何孩子的節點時,可能有一個節點會匹配,所以我需要添加這個父節點作爲潛在匹配。 當我將夫妻​​關在一起而沒有得到匹配時,訪問了「可能的」節點,我需要再次通過整棵樹再次找到那些(偶數次)。 我有一個醜陋的解決方案:首先獲取樹級別並在for-loop中重複過濾以不添加這些無子節點。這很糟糕,因爲不準確。通過刪除拖尾匹配的節點遞歸地過濾對象

我想調用一次過濾來獲得結果。

在下面的代碼中,經過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 
] 

回答

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 => ...) 
+0

嗯,此陣列被結合,以查看,所以我不能修改層級。通過拼合你可以檢查是否有一個空的節點是正確的?所以,做過濾,比扁平化,並檢查是否仍有空節點,如果是的話再次過濾。這可以提高準確性,但仍需要執行多個過濾 – Monika

+0

我可能並不完全瞭解您的問題。我上面寫的函數不會修改現有的層次結構,它會返回一個帶有平坦結果的新數組,然後您可以過濾一次以獲得結果。 –

+0

你能解釋一下過濾的想法嗎?我運行你的代碼(假設typo(?)'recGetCat()'應該''recFlatten()'),並且我得到了扁平對象的數組。我現在可以過濾以搜索例如根和我會得到像以前一樣的對象 - 包含兒童的不匹配 – Monika

0

你可以使用一個recursice方法爲孩子,如果某些名字匹配或某些孩子匹配,然後創建一個新的對象與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; }

+0

是的,它的工作原理應該:)只是我需要避免手動創建對象。事實上,這些節點是其他對象的抽象,並保存它們的引用。在此過濾器特性中只使用屬性'name'和'children',所以我只用它們來簡化問題,使用簡單的模型 – Monika

+0

@Monika,請參閱編輯,現在用['Object.assign'](https:// developer .mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign),它會生成一個新對象,其中包含原始屬性的所有屬性,而不會改變源。 –