繁体   English   中英

递归JavaScript函数,通过其UID定位对象

[英]Recursive JavaScript function to locate an object by its UID

我在返回在此分层树中找到的元素时遇到问题。 例如,如果我选择的项目是:

{
 "UID": 49,
 "GUID": "",
 "LocationName": "Doctor Smith's Office",

 "LocationType": {
    "UID": 2,
    "LocationTypeName": "Practice",
    "Description": "other location"
 }
}

我将把UID匹配到下面的对象数组。

 { UID: 2, GUID: "", LocationName: "USA", ParentLocation: null, subs: [{ UID: 42, GUID: "", LocationName: "New Jersey", Description: "", subs: [{ UID: 3, GUID: "", LocationName: "Essex County", ParentLocation: null, "subs":[ UID: 4, LocationName: "Newark", ParentLocation: 3, "subs": [ { "UID": 49, "GUID": "", "LocationName": "Doctor Smith's Office", "LocationType": { "UID": 2, "LocationTypeName": "Practice", "Description": "other location" }, "subs": [ { "HostID": 38, "HostName": "Ocean Host", } ] } ] ] } ] }] }; 

 let foundItem = this.findInTreeView(this.treeviewData[0], node.selectedNode); // find selected node in treeview nav // param: data - the treeview dataset // param: selected - the selected node to be searched for in param 'data' findInTreeView(data: any, selected: any ) { let found; if (this.foundInTree(data, selected)) { return data; } let elem; let ary = data.subs; for (var i=0; i < ary.length; i++) { elem = ary[i]; if (this.foundInTree(elem, selected)) { // *** PROBLEM: If func has return true, I want to return the 'elem' object. return elem; } } for (var i=0; i < ary.length; i++) { elem = ary[i]; if (elem.subs !== undefined) { // recurse subs array let found = this.findInTreeView(elem, selected); if (found) { return elem; } } } //return elem; } foundInTree(treeItem, node) { if (treeItem.UID === node.UID) { return true; } else { return false; } } 

使用递归化reduce函数会容易得多,如下所示:

 const input={UID:2,GUID:"",LocationName:"USA",ParentLocation:null,subs:[{UID:42,GUID:"",LocationName:"New Jersey",Description:"",subs:[{UID:3,GUID:"",LocationName:"Essex County",ParentLocation:null,"subs":[{UID:4,LocationName:"Newark",ParentLocation:3,"subs":[{"UID":49,"GUID":"","LocationName":"Doctor Smith's Office","LocationType":{"UID":2,"LocationTypeName":"Practice","Description":"other location"},"subs":[{"HostID":38,"HostName":"Ocean Host",}]}]}]}]}]}; const findUIDObj = (uid, parent) => { const { UID, subs } = parent; if (UID === uid) { const { subs, ...rest } = parent; return rest; } if (subs) return subs.reduce((found, child) => found || findUIDObj(uid, child), null); }; console.log(findUIDObj(49, input)) 

您可以使用显式函数来搜索所需的UID

 function find(array, UID) { var object; array.some(o => { if (o.UID === UID) { return object = o; } return object = find(o.subs, UID); }); return object; } var object = { UID: 2, GUID: "", LocationName: "USA", ParentLocation: null, subs: [{ UID: 42, GUID: "", LocationName: "New Jersey", Description: "", subs: [{ UID: 3, GUID: "", LocationName: "Essex County", ParentLocation: null, subs: [{ UID: 4, LocationName: "Newark", ParentLocation: 3, subs: [{ UID: 49, GUID: "", LocationName: "Doctor Smith's Office", LocationType: { UID: 2, LocationTypeName: "Practice", Description: "other location" }, subs: [{ HostID: 38, HostName: "Ocean Host", }] }] }] }] }] }; console.log(find([object], 49)); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

一种实现方法是编写一个相当普通的版本的树查找函数,然后针对您的特定问题进行配置。 在这里,我们选择通过匹配所提供的UID进行测试,通过查看subs属性来划分为子级,然后通过去除subs属性来转换结果:

 const searchTreeDF = (kids, test, convert, node) => test(node) // depth-first search ? convert(node) : (kids(node) || []).reduce( (found, child) => found || searchTreeDF(kids, test, convert, child), false ) const subs = node => node.subs const matchId = (uid) => (item) => item.UID === uid const convert = ({subs, ...rest}) => ({...rest}) const findUid = (uid, tree) => searchTreeDF(subs, matchId(uid), convert, tree) // ... const tree = {"GUID": "", "LocationName": "USA", "ParentLocation": null, "UID": 2, "subs": [{"Description": "", "GUID": "", "LocationName": "New Jersey", "UID": 42, "subs": [{"GUID": "", "LocationName": "Essex County", "ParentLocation": null, "UID": 3, "subs": [{"LocationName": "Newark", "ParentLocation": 3, "UID": 4, "subs": [{"GUID": "", "LocationName": "Doctor Smith's Office", "LocationType": {"Description": "other location", "LocationTypeName": "Practice", "UID": 2}, "UID": 49, "subs": [{"HostID": 38, "HostName": "Ocean Host"}]}]}]}]}]} console.log(findUid(49, tree)) 

但是,如果我们不想直接传递UID ,而是想传递具有自己的UID属性的元素,则可以编写

const matchElem = (elem) => (item) => elem.UID === item.UID

然后执行以下操作:

const findUid2 = (elem, tree) => searchTreeDF(subs, matchElem(elem), convert, tree)
// ...
findUid2({UID: 49}, tree)

或者,如果我们不想转换结果,并保留subs属性,我们可以只提供一个用于convert的标识函数:

const findUid = (uid, tree) => searchTreeDF(subs, matchId(uid), x => x, tree)

或者我们可以随意混合搭配。 另请注意,该配置不必使用命名函数。 我们可以轻松地编写

const findUid = (uid, tree) => searchTreeDF(
  node => node.subs || [], 
  (item) => item.UID === uid,
  ({subs, ...rest}) => ({...rest}), 
  tree
)

泛型函数并不总是正确的答案。 但是它们可以帮助区分那些与我们正在编写的更基本的算法有所不同的东西。 我认为在这种情况下,它有助于使事情更易于维护。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM