Voici le problème:
// Obtenir le nom le plus long
// Ecrire une fonction, getLongestName, qui prend un objet. L'objet représente un arbre généalogique. Renvoie le nom le plus long de la famille.
Ceci est le code mais il renvoie une erreur:
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'
Quand j'exécute le code ci-dessus, j'obtiens l'erreur suivante: ReferenceError: descendentLongestName n'est pas défini
Qu'est-ce que j'ai fait de mal?
6 Réponses :
let scope est spécifique au bloc donc si vous voulez l'utiliser, déclarez-le en dehors du bloc sinon utilisez 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; }
quand j'exécute votre code ci-dessus, getLongestName (family) renvoie ''
Vous pouvez utiliser deux parties, une pour vérifier la clé et une partie récursive pour obtenir les clés des objets imbriqués.
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));
Je ne sais pas comment corriger votre code, mais j'aimerais suggérer une nouvelle solution.
L'idée est de décomposer votre problème en deux parties:
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)));
sort ()
fait muter le tableau. Il peut être conseillé de le copier d'abord superficiellement. par exemple. [... ary] .sort (/*...*/)
@customcommander: oui, j'ai remplacé plus long
par une meilleure implémentation.
Puisqu'une clé et sa valeur peuvent être en concurrence pour avoir la chaîne la plus longue, il peut être judicieux d'utiliser Object.entries
dans une fonction récursive:
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));
Utilisez une boucle for ... in
pour parcourir les paires clé-valeur dans l'objet family
. Si la valeur est un objet, utilisez la récursivité pour parcourir cet objet, pour voir si la clé de cet objet est plus longue que l'une des clés qui le précède. Renvoie la clé la plus longue (nom).
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));
Je commencerais par une simple fonction traversée
-
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" } ]
Cela sépare le parcours de votre arbre de l'opération que vous souhaitez effectuer sur les valeurs de l'arbre . Maintenant, nous implémentons une simple fonction 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" // ]
Comme vous pouvez le voir, écrire longestName
est facile maintenant que nous le faisons Nous n'avons pas à nous préoccuper de la logique de parcours en même temps.
Développez l'extrait ci-dessous pour vérifier les résultats dans votre propre navigateur -
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
S'il y avait d'autres données dans l'arborescence, vous pouvez voir comment il serait facile d'écrire d'autres fonctions en utilisant également 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" // ]
Vous devez déclarer
descendentLongestName
là où vous déclarezlongestName
au lieu de l'intérieur du blocif
. Et vous n'avez pas besoin delet
dans ce dernierif
carlongestName
est déjà déclaré.