题目是:
给一个数据结构如下 var data = [ { "name": "手机", "childs": [ { "name": "iPhone", "childs": [ {"name": "iPhone X"}, {"name": "iPhone XR"}, {"name": "iPhone XS"}, ] }, { "name": "HUAWEI", "childs": [ {"name": "HUAWEI Mate 20"}, {"name": "HUAWEI Mate 20 X"}, {"name": "HUAWEI Mate 20 Pro"}, ] } ] }
];
然后让封装一个函数, 根据名称得到其遍历的路径. 例如参数是 HUAWEI Mate 20. 那么函数返回 手机 / HUAWEI/HUAWEI Mate 20. 要求函数可以适用多层的数据结构, 例如上面的数据只有三层深度, 如果扩展为 10 层的话函数仍然可以适用. 这个题目的其实就是一个树的遍历, 然后返回这个遍历路径. 但是想了半天没想到如何写
![]() | 1 zakarycode 2019-05-21 09:47:54 +08:00 递归考虑下 |
![]() | 2 Chrisssss 2019-05-21 09:50:13 +08:00 递归,把当前的路径传下去就行了。 |
3 geehero 2019-05-21 09:50:33 +08:00 via iPhone To iterate is human, to recurse divine. |
4 lyshine OP 递归我试了, 往下传路径的时候似乎有问题, 各位答主最好能给个可以运行的代码 |
5 voidbit 2019-05-21 10:09:36 +08:00 via iPhone ![]() 用栈吖,回溯法 |
![]() | 6 asukanoir 2019-05-21 10:11:34 +08:00 @lyshine 虽然好多年不写代码了。。。给个愚见:利用栈的思路,执行递归,先深度再广度,然后返回的时候上层调用函数自然会保留父节点路径,按说没有你说的这种问题吧。 |
![]() | 7 wly19960911 2019-05-21 10:35:55 +08:00 ![]() function findPhone(name, node, path ) { const newPath = path + '/' + node.name; if (node.name != name) { if (node.childs) { for (let item of node.childs) { const result = findPhone(name, item, newPath) if(result) { return result; } } return false; } else { return false; } } else { return newPath; } } findPhone('iPhone X', data[0], ''); 实现上可能复杂了点,但是我感觉没必要用栈就是。还得维护状态,直接用基础类型参数连状态都不用管 |
8 noviceiOS 2019-05-21 10:49:13 +08:00 ![]() function getPathByName(data,objName){ var cOnf= {}; function getConf(_data,_path){ for(var i in _data){ var __path = _path? _path + "/"+_data[i].name:_data[i].name; conf[_data[i].name] = __path; if(_data[i].childs){ getConf(_data[i].childs,__path); } } } getConf(data,""); return conf[objName]; } alert(getPathByName(data,"HUAWEI Mate 20 Pro")); |
9 lyshine OP @wly19960911 首先感谢你的回答. 我感觉这个 result 很关键. 这个我就没想到. 我当时就没想到如何在递归中摒弃不需要的路径 |
10 noviceiOS 2019-05-21 10:59:52 +08:00 function getPathByName(data,objName){ var path=""; function getConf(_data,_path){ for(var i in _data){ var __path = _path? _path + "/"+_data[i].name:_data[i].name; if(objName==_data[i].name){ path = __path; return; } if(_data[i].childs){ getConf(_data[i].childs,__path); } } } getConf(data,""); return path; } alert(getPathByName(data,"HUAWEI Mate 20 Pro")); |
![]() | 12 shyling 2019-05-21 11:16:29 +08:00 为什么不直接预处理一下 { name: a, childs: [b,c,d] } 转成 { b: 'a/b', ... } |
13 Laumm 2019-05-21 11:39:38 +08:00 |
14 Laumm 2019-05-21 11:43:58 +08:00 query(data[0],"name") |
15 Aliennnnnn 2019-05-21 11:50:57 +08:00 |
![]() | 16 geelaw 2019-05-21 12:19:48 +08:00 via iPhone 先 preprocess 把结构 flatten,每次询问时进行路径压缩。 但是这个数据结构品位很差,因为 child 的复数是一 children。 |
![]() | 17 Sapp 2019-05-21 12:21:31 +08:00 ``` const data = [ { name: "手机", childs: [ { name: "iPhone", childs: [ { name: "iPhone X" }, { name: "iPhone XR" }, { name: "iPhone XS" } ] }, { name: "HUAWEI", childs: [ { name: "HUAWEI Mate 20" }, { name: "HUAWEI Mate 20 X" }, { name: "HUAWEI Mate 20 Pro" } ] } ] } ]; const query = (items, arg) => items.map(item => { // 如果名字相同 if (item.name === arg) return item.name; // 如果没有子集 if (!item.childs) return null; // 遍历查找子级,并过滤不相干内容 const childrenResult = query(item.childs, arg).filter(item => !!item); // 找到了内容,携带当前名字一同返回上一级 if (childrenResult.length) return `${item.name} => ${childrenResult[0]}`; // 子级也未找到 return null; }).filter(item => !!item); query(data, 'HUAWEI Mate 20 Pro') // ["手机 => HUAWEI => HUAWEI Mate 20 Pro"] ``` 没做任何优化,还是挺好懂得吧 |
18 jjwjiang 2019-05-21 13:41:30 +08:00 这不就是最纯粹的递归吗?怎么看楼上一堆还传 path 进去的,还有写 2 个函数的?这就是最简单的递归模式啊 function getPath(data, name ) { for (var i = 0; i < data.length; i++) { if (data[i].name == name) return "/" + name; else if (data[i].childs) { var next = getPath(data[i].childs, name); if (next) return "/" + data[i].name + next; } } return ""; } getPath(data, "HUAWEI Mate 20 X"); |
19 zqx 2019-05-21 13:47:38 +08:00 via Android 有人考虑过把结构压扁,然后用字符串操作吗 |
20 panshao 2019-05-21 14:41:55 +08:00 |
![]() | 21 poisedflw 2019-05-21 15:26:07 +08:00 function getPhonePath(data = [], name, prefix = []) { for (let i = 0, len = data.length; i < len; i++) { let tmp = data[i]; if (prefix.isFind) return prefix; prefix.push(tmp.name); if (tmp.name === name && (prefix.isFind = true)) return prefix; if (tmp.childs) getPhonePath(tmp.childs, name, prefix) !prefix.isFind && prefix.pop(); } return [...prefix]; } console.log(getPhonePath(data, "HUAWEI Mate 20 X")); 加个标志,可以少一层循环。 |
![]() | 22 nikandaoleshenme 2019-05-21 16:38:33 +08:00 @lyshine 竟然从这跑去 sf 了 |
![]() | 23 redbuck 2019-05-21 17:09:35 +08:00 |
![]() | 24 redbuck 2019-05-21 17:22:11 +08:00 @redbuck 错了 reduce 第二个参数应该是'' function name2path(list, name, path) { return list.reduce((prev, item) => { // ... }, '') } |
25 lyshine OP @nikandaoleshenme 这都被你发现了. 哈哈哈今天刚注册的 |
28 aihimmel 2019-05-21 23:55:55 +08:00 python 写的 def iter_names(a, prefix=''): for i in a: if 'childs' in i: ite(i['childs'], prefix=prefix + i['name'] + '/') else: print prefix + i['name'] |
![]() | 29 brucewuio 2019-05-24 15:06:34 +08:00 function retrievePath(phoneName,obj) { for (let i in obj) { if (obj[i]['childs']) { let returnStr = retrievePath(phoneName,obj[i]['childs']) if (returnStr !== '') return '/' + obj[i]['name'] + returnStr }else { if (phOneName=== obj[i]['name']) { return '/' + obj[i]['name'] } } } } |
30 takemyhate 2023-05-18 10:59:39 +08:00 function findPath(data, target) { let path = ""; // 用于存储路径 function traverse(node, currentPath) { if (node.name === target) { path = currentPath; // 找到目标节点时更新路径 return; } if (node.childs) { for (let i = 0; i < node.childs.length; i++) { const child = node.childs[i]; const newPath = currentPath ? `${currentPath} / ${child.name}` : child.name; traverse(child, newPath); // 递归遍历子节点 } } } traverse(data, ""); return path; } // 测试 var data = [ { name: "手机", childs: [ { name: "iPhone", childs: [ { name: "iPhone X" }, { name: "iPhone XR" }, { name: "iPhone XS" }, ], }, { name: "HUAWEI", childs: [ { name: "HUAWEI Mate 20" }, { name: "HUAWEI Mate 20 X" }, { name: "HUAWEI Mate 20 Pro" }, ], }, ], }, ]; console.log(findPath(data[0], "HUAWEI Mate 20")); // 输出 "手机 / HUAWEI / HUAWEI Mate 20" //findPath 函数接受两个参数:data 是树的根节点,target 是要查找的目标节点的名称。函数通过递归遍历树的节点,每次遍历时更新当前路径,并检查当前节点是否为目标节点,如果是则将路径存储到 path 变量中。最终返回得到的路径。这个可以适用于多层的数据结构,因为它通过递归方式遍历树的每个节点,不论树的深度有多大,都能正确地找到路径。 |