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

时间:2019-04-01 16:35:40

标签: javascript object recursion nested key

下面是问题:

//获取最长名称

///编写一个带有对象的函数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

我做错了什么?

6 个答案:

答案 0 :(得分:1)

您可以使用两部分,一部分用于检查键,而递归部分用于获取嵌套对象的键。

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));

答案 1 :(得分:1)

我不知道如何解决您的代码,但我想提出一个新的解决方案。

想法是将您的问题分解为两个部分:

  • 递归地从嵌套对象中找到所有键
  • 从字符串数组中找到最长的一个

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)));

答案 2 :(得分:0)

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; 
}


答案 3 :(得分:0)

由于键及其值可以争夺具有最长字符串的字符串,因此在递归函数中使用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));

答案 4 :(得分:0)

使用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)); 

答案 5 :(得分:0)

我将从一个简单的函数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" } ]