2 votes

Traverser dynamiquement les clés d'un objet de profondeur inconnue

J'ai une sorte de question étrange - peut-être une question stupide - qui nécessite quelques explications, alors merci de patienter avec moi. Fondamentalement, je me demande s'il existe un moyen de traverser un objet de profondeur inconnue en JavaScript sans utiliser de récursivité.

Par exemple, disons que j'ai un objet de profondeur inconnue. Il peut ressembler à ceci :

let obj_depth2 = {
  male:
    { short: 0, tall: 0 },
  female:
    { short: 0, tall: 0 }
  }

ou peut-être comme ceci :

let obj_depth3 = {
  male: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  },
  female: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  }
}

L'obj peut être encore plus profond. Je ne connaîtrai pas sa profondeur à l'avance.

Supposons en outre que j'aurai un arr qui ressemble à ceci, et qui correspondra à la profondeur de l'obj en longueur.

let arr_depth2 = ["male", "short"];

ou

let arr_depth3 = ["male", "tall", "basketball"];

J'aurai une boucle dans laquelle je générerai, disons, 1 000 de ces arr que j'utiliserai ensuite pour ajouter 1 à l'obj de profondeur inconnue. Tous les arr auront la même longueur (2 ou 3, ou plus) et correspondront toujours à la profondeur de l'obj. Mais la profondeur changera et je veux écrire une seule fonction pour couvrir toutes les situations.

Pour être clair, je n'aurai PAS une situation où j'ai un obj de profondeur 2 et un arr de longueur 3. Les profondeurs et les longueurs correspondront toujours pour les 1 000 itérations à chaque fois.

Ma question est la suivante. Existe-t-il un moyen de parcourir l'obj pour ajouter 1 à la valeur de la paire clé-valeur "la plus profonde" à laquelle je dois accéder sans utiliser de récursivité ?

Puis-je construire quelque chose comme ceci ?

obj["male"]["short"] += 1;

Je sais que je peux utiliser la récursivité pour atteindre la profondeur la plus basse de l'obj, ajouter 1 à la valeur appropriée et le return, reconstruire l'obj à mesure que la fonction récursive continue de return, cela signifie que je devrais reconstruire l'obj pour chaque valeur à chaque fois et remplacer l'obj que je viens de construire sur l'itération précédente, juste pour ajouter 1 à une partie de l'obj. Cela semble juste mauvais, mais peut-être que cela n'a pas d'importance.

Merci d'avance.

1voto

Nick Parsons Points 2103

Vous pouvez le faire avec .reduce() pour parcourir votre objet, où l'accumulateur garde en mémoire votre objet actuel lors de la traversée. Une fois que votre réduction est terminée, vous aurez l'objet le plus profondément imbriqué dans votre chemin, que vous pouvez ensuite utiliser le dernier élément de votre tableau comme clé pour modifier la valeur. Comme vous l'avez dit, il n'est pas nécessaire de faire de la récursion si vous êtes satisfait de simplement muter l'objet original:

const obj = {male:{short:{basketball:0,soccer:0},tall:{basketball:0,soccer:0}},female:{short:{basketball:0,soccer:0},tall:{basketball:0,soccer:0}}}
const arr = ["male", "tall", "basketball"];

const modify = (obj, [...keys]) => {
  const last_key = keys.pop();        
  const last_obj = keys.reduce((o, k) => o[k], obj);
  last_obj[last_key] += 1;
}

modify(obj, arr);
console.log(obj);

1voto

Nick Points 2417

Si vous essayez de modifier l'objet en place, vous pouvez essentiellement utiliser un pointeur pour parcourir l'objet jusqu'à ce que vous atteigniez la dernière clé, puis la définir.

const obj_depth3 = {
  male: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  },
  female: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  }
}

const addOneTo = (obj, path) => {
  const finalProp = path.pop();
  const pointer = path.reduce((pointer, key) => pointer[key], obj);
  pointer[finalProp]++;
}

addOneTo(obj_depth3, ["male", "short", "soccer"])

console.log(obj_depth3);

0voto

Vous pouvez accéder en toute sécurité à un objet imbriqué dans votre cas décrit en utilisant la fonction reduce :

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

Ensuite, vous pouvez accéder à votre objet souhaité ['male']['short'] de manière similaire :

let shortMale = getNestedObject(obj_depth3, ['male', 'short'])

Et vous pouvez effectuer l'opération souhaitée sur l'objet :

shortMale.basketball += 1

Pour plus d'informations sur la fonction getNestedObject, voir : https://hackernoon.com/accessing-nested-objects-in-javascript-f02f1bd6387f

0voto

The Bomb Squad Points 1840

Voici une formule pour obtenir toutes les parties d'un objet de taille inconnue une fois que vous pouvez appeler le nom du dossier en JavaScript Object.entries(votreObjet) Cela renvoie un tableau de toutes les données de votre objet afin que vous puissiez facilement y itérer. Je vais renvoyer vos données dans l'exemple pour vous montrer comment fonctionne Object.entries

const obj_depth3 = {
  male: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  },
  female: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  }
}
console.log(Object.entries(obj_depth3));
//vous pouvez toujours utiliser une autre console comme celle de l'inspecteur pour voir comment fonctionne le tableau, mais il contient toute la profondeur et les informations :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X