3
votes

"Impossible de trouver le nom de propriété non défini" lors de la création de données imbriquées

J'essaye de créer un objet arborescent imbriqué en utilisant un ensemble de données existant. L'ensemble de données d'origine est:

var obj = new Proxy({}, { 
    get: function(target, name) {
        if (!(name in target)) {
            console.log("Non-existant property '" + name + "'");
            var val = target[name] = typeof(target);  //Returning reference to already created object
            return val;  
        }
    }
}); 

Je veux que mes données finales ressemblent à ceci:

"TypeError: Cannot set property 'B1' of undefined

Voici mes progrès jusqu'à présent.

var obj = {};

for(i = 0; i< raw_data.length; i++) { 
  var [x,y,z,value] = raw_data[i];
  obj[x][y][z] = value;  
}

Je boucle sur les données et j'exécute les valeurs de propriété de manière récursive sur une donnée vide. Par exemple: Dans la 1ère itération, j'ai défini obj ['A1'] ['B1'] ['C1'] = 1 . Cependant, cela pose problème car la première récursivité ( obj ['A1' ]) renverra undefined donc l'erreur suivante:

{'A1': 
  {'B1': {'C2': 2, 'C1': 1}, 
   'B2': {'C2': 6, 'C1': 4}
  }, 
 'A2': 
  {'B1': {'C2': 10, 'C1': 8}, 
   'B2': {'C2': 14, 'C1': 12}
  }
}


5 commentaires

Lorsque vous essayez d'accéder à la clé A1 la première fois qu'elle n'existe pas. Vous devez donc le créer. La même chose se produit lorsque vous accédez à la touche B1 de l'objet A1 .


Ouais, je dois en quelque sorte renvoyer un objet proxy sur la référence créée précédemment, mais je ne sais pas vraiment comment faire cela.


Vous n'avez pas besoin d'un objet proxy. Vous pouvez certainement en utiliser un, mais ce serait un problème XY. En substance, vous devez vérifier si obj [key] existe et s'il ne l'instancie pas avant d'interagir avec lui obj [key] = {} .


Pourquoi toutes les valeurs finales 1 dans la sortie souhaitée.


@MarkMeyer désolé que ce soit une faute de frappe. Édité.


3 Réponses :


1
votes

Vous pouvez utiliser une approche dynamique et réduire les clés données jusqu'au dernier élément et le prendre comme accesseur pour attribuer la valeur.

À l'intérieur de l'obtention du bon objet interne, un objet par défaut est assigné à une propriété, si le l'objet n'existe pas.

.as-console-wrapper { max-height: 100% !important; top: 0; }
function setValue(object, path, value) {
    var last = path.pop();
    path.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
    return object;
}

var raw_data = [["A1", "B1", "C1", 1], ["A1", "B1", "C1", 2], ["A1", "B1", "C2", 3], ["A1", "B2", "C1", 4], ["A1", "B2", "C1", 5], ["A1", "B2", "C2", 6], ["A1", "B2", "C2", 7], ["A2", "B1", "C1", 8], ["A2", "B1", "C1", 9], ["A2", "B1", "C2", 10], ["A2", "B1", "C2", 11], ["A2", "B2", "C1", 12], ["A2", "B2", "C1", 13], ["A2", "B2", "C2", 14], ["A2", "B2", "C2", 15]],
    object = raw_data.reduce((r, a) => setValue(r, a.slice(0, -1), a[a.length - 1]), {});

console.log(object);


0 commentaires

1
votes

Avec ES6, vous pourriez faire

for(i = 0; i< raw_data.length; i++) { 
  var [x,y,z,value] = raw_data[i];

  obj[x] && obj[x][y] ? obj[x][y][z] = value : obj[x] ? obj[x][y] = {[z] : value} : obj[x] = {[y] : {[z] : value}};
}

Grâce à ComputedPropertyName (voir https://stackoverflow.com/a/2274327/3057341 )


0 commentaires

0
votes

Voici ma solution de code à votre problème. J'ai parcouru chaque élément du tableau de tableaux et peuplé l'objet en suivant la structure d'imbrication.

const raw_data = [
    ["A1", "B1", "C1", 1],
    ["A1", "B1", "C2", 2],
    ["A1", "B2", "C1", 3],
    ["A1", "B2", "C1", 4],
    ["A1", "B2", "C2", 5],
    ["A1", "B2", "C2", 6],
    ["A2", "B1", "C1", 7],
    ["A2", "B1", "C1", 8],
    ["A2", "B1", "C2", 9],
    ["A2", "B1", "C2", 10],
    ["A2", "B2", "C1", 11],
    ["A2", "B2", "C1", 12],
    ["A2", "B2", "C2", 13],
    ["A2", "B2", "C2", 14]
    ];

let obj = {};
raw_data.forEach(element => {
    for(let i=0; i<4; i++){
        let first_elem = element[0];
        let second_elem = element[1];
        let third_elem = element[2];
        let fourth_elem = element[3];
        switch(i){
            case 0:
                if(!(first_elem in obj)){
                    obj[first_elem] = {};
                }
            break;
            case 1:
                if(!(second_elem in obj[first_elem])){
                    obj[first_elem][second_elem] = {};
                }
            break;
            case 2:
                if(!(third_elem in obj[first_elem][second_elem])){
                    obj[first_elem][second_elem][third_elem] = null;
                }
            break;
            case 3:
                if(fourth_elem != obj[first_elem][second_elem][third_elem]){
                    obj[first_elem][second_elem][third_elem] = fourth_elem;
                }
            break;
        }
    }  
});    
console.log(obj);


0 commentaires