繁体   English   中英

Javascript:递归问题 --> 返回深度嵌套对象中最长的键值

[英]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.

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