2
votes

Javascript: Problème de récursivité -> Renvoie la valeur de clé la plus longue dans un objet profondément imbriqué

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?


1 commentaires

Vous devez déclarer descendentLongestName là où vous déclarez longestName au lieu de l'intérieur du bloc if . Et vous n'avez pas besoin de let dans ce dernier if car longestName est déjà déclaré.


6 Réponses :


0
votes

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



1 commentaires

quand j'exécute votre code ci-dessus, getLongestName (family) renvoie ''



1
votes

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


0 commentaires

1
votes

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:

  • rechercher toutes les clés d'un objet imbriqué, de manière récursive
  • trouver la plus longue parmi un tableau de chaînes

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 commentaires

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.



0
votes

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


0 commentaires

0
votes

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


0 commentaires

0
votes

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"
// ]


0 commentaires