[英]Javascript: Recursion Problem --> Return the longest key value in a deeply nested object
下面是问题:
// 获取最长名称
// 编写一个函数 getLongestName,它接受一个对象。 该对象代表一个家谱。 返回家族中最长的名字。
这是代码,但它返回一个错误:
let family = {
'Beverly Marquez': {
'Nina Rhone': {
'William Rhodes': null,
'Paul Nell': null,
'Sir Paddington the Fourth, of the county Wilstonshire': null
}
}
};
function getLongestName (family){
let longestName = '';
for (let key in family){
let value = family[key]
console.log(value)
if (typeof value === 'object'){
let descendentLongestName = getLongestName (value)
}
else {
descendentLongestName = value
}
if (descendentLongestName.length > longestName.length){
let longestName = descendentLongestName
}
}
return longestName;
}
getLongestName(family); // => 'Sir Paddington the Fourth, of the county Wilstonshire'
当我运行上面的代码时,出现以下错误:ReferenceError:descendentLongestName 未定义
我做错了什么?
您可以使用两部分,一个用于检查键,一个递归部分用于获取嵌套对象的键。
function getLongestKey(object, keys = []) { return Object.keys(object).reduce((r, k) => { if (!r || r[0].length < k.length) { r = [k]; } else if (r[0].length === k.length) { r.push(k); } return object[k] && typeof object[k] === 'object' ? getLongestKey(object[k], r) : r; }, undefined) } let family = { 'Beverly Marquez': { 'Nina Rhone': { 'William Rhodes': null, 'Paul Nell': null, 'Sir Paddington the Fourth, of the county Wilstonshire': null } } }; console.log(getLongestKey(family));
我不知道如何修复您的代码,但我想建议一个新的解决方案。
这个想法是将您的问题分解为两部分:
let longest = ary => ary .reduce((max, x) => x.length > max.length ? x : max, ''); let allKeys = obj => obj ? Object.keys(obj).concat( ...Object.values(obj).map(allKeys)) : []; // let family = { 'Beverly Marquez': { 'Nina Rhone': { 'William Rhodes': null, 'Paul Nell': null, 'Sir Paddington the Fourth, of the county Wilstonshire': null, } } }; console.log(longest(allKeys(family)));
let 作用域是块特定的,所以如果你想使用它,那么在块之外声明它,否则使用 var
function getLongestName (family){
let longestName = '';
for (let key in family){
let value = family[key]
console.log(value)
let descendentLongestName='';
if (typeof value === 'object'){
descendentLongestName = getLongestName (value)
}
else {
descendentLongestName = value
}
let longestName;
if (descendentLongestName && descendentLongestName.length > longestName.length){
longestName = descendentLongestName
}
}
return longestName;
}
由于键及其值可能会竞争最长的字符串,因此在递归函数中使用Object.entries
可能是有意义的:
var family = { 'Beverly Marquez': { 'Nina Rhone': { 'William Rhodes': null, 'Paul Nell': null, 'Sir Paddington the Fourth, of the county Wilstonshire': null, } } }; const longest = (obj, cur = '') => Object.entries(obj).reduce((max, [key, val]) => { const candidate = (val && longest(val, max)) || key; return candidate.length > max.length ? candidate : max; }, cur); console.log(longest(family));
使用for...in
循环遍历family
对象中的键值对。 如果该值是一个对象,则使用递归遍历该对象,以查看该对象的键是否比它之前的任何键都长。 返回最长的键(名称)。
function getLongestName(family) { let longest = ""; for (let key in family) { //create initial longest if (key.length > longest.length) { longest = key; } let value = family[key]; //if value is an object if (typeof value === "object") { //use recursion to get the key-values of that value let descendant = getLongestName(value); //if descendant's name is longer than longest, assign it to 'longest' if (descendant.length > longest.length) { longest = descendant; } } } return longest; } console.log(getLongestName(family));
我将从一个简单的函数traverse
-
const traverse = function* (t = {})
{ if (t == null) return
for (const [ name, children ] of Object.entries(t))
{ yield name
yield* traverse(children)
}
}
console.log(Array.from(traverse(family)))
// [ "Beverly Marquez"
// , "Nina Rhone"
// , "William Rhodes"
// , "Paul Nell"
// , "Sir Paddington the Fourth, of the county Wilstonshire"
// ]
这将树的遍历与您希望对树的值执行的操作分开。 现在我们实现一个简单的longestName
函数——
const longestName = (t = {}) =>
{ let r = ""
for (const name of traverse(t))
if (name.length > r.length)
r = name
return r
}
console.log(longestName(family))
// Sir Paddington the Fourth, of the county Wilstonshire
如您所见,现在我们不必同时关注遍历逻辑,因此编写longestName
名称很容易。
展开下面的代码段以在您自己的浏览器中验证结果 -
let family = { 'Beverly Marquez': { 'Nina Rhone': { 'William Rhodes': null, 'Paul Nell': null, 'Sir Paddington the Fourth, of the county Wilstonshire': null } } } const traverse = function* (t = {}) { if (t == null) return for (const [ name, children ] of Object.entries(t)) { yield name yield* traverse(children) } } const longestName = (t = {}) => { let r = "" for (const name of traverse(t)) if (name.length > r.length) r = name return r } console.log(longestName(family)) // Sir Paddington the Fourth, of the county Wilstonshire console.log(Array.from(traverse(family))) // [ "Beverly Marquez" // , "Nina Rhone" // , "William Rhodes" // , "Paul Nell" // , "Sir Paddington the Fourth, of the county Wilstonshire" // ]
如果树中还有其他数据,您可以看到使用traverse
编写其他函数是多么容易 -
const myTree = { name: "Alice" , gender: "F" , children: [ { name: "Bob" , gender: "M" , children: [ { name: "Charles" , gender: "M" } ] } ] } const traverse = function* ({ children = [], ...t }) { yield t for (const child of children) yield* traverse(child) } const filter = function* (test, t = {}) { for (const leaf of traverse(t)) if (test(leaf)) yield leaf } const byGender = (q = "", t = {}) => filter(node => node.gender === q, t) console.log(Array.from(byGender("M", myTree))) // [ { name: "Bob", gender: "M" }, { name: "Charles", gender: "M" } ] console.log(Array.from(byGender("F", myTree))) // [ { name: "Alice", gender: "F" } ]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.