Javascript: проблема рекурсии -> вернуть самое длинное значение ключа в глубоко вложенном объекте - PullRequest
2 голосов
/ 01 апреля 2019

Ниже приведена проблема:

// Получить длинное имя

// Напишите функцию 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 ]

1 голос
/ 01 апреля 2019

Я не знаю, как исправить ваш код, но я бы хотел предложить новое решение.

Идея состоит в том, чтобы разбить вашу проблему на две части:

  • найти все ключи от вложенного объекта, рекурсивно
  • найти самый длинный из массива строк

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)));
1 голос
/ 01 апреля 2019

Вы можете использовать две части, одну для проверки ключа и рекурсивную часть для получения ключей вложенных объектов.

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));
0 голосов
/ 05 июля 2019

Я бы начал с простой функции 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" } ]
0 голосов
/ 04 июля 2019

Используйте цикл 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)); 
0 голосов
/ 02 апреля 2019

Поскольку ключ и его значение могут конкурировать за самую длинную строку, имеет смысл использовать 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));
0 голосов
/ 01 апреля 2019

пусть область действия зависит от блока, поэтому, если вы хотите использовать его, объявите его вне блока, в противном случае используйте 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; 
}


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...