1

Array of objects where the hierarchy objects is stored in hierarchy
property. nesting of objects are done based on this hierarchy

[  
  {
    "hierarchy" : ["obj1"],  
    "prop1":"value" 
  },
  {  
    "hierarchy" : ["obj1","obj2"],  
    "prop2":"value",  
    "prop3":"value"  
  },  
  {  
    "hierarchy" : ["obj1","obj3"],  
    "prop4":"value",  
    "prop5":"value"  
  },  
  {  
    "hierarchy" : ["obj1","obj3", "obj4"],  
    "prop6":"value",  
    "prop7":"value",  
    "arr"  :["val1", "val2"]  
  }
]  

Expected nested object, hierarchy key removed here

{  
  "obj1":{  
    "prop1":"value",  
    "obj2" : {  
      "prop2":"value",  
      "prop3":"value"  
    },  
    "obj3":{  
      "prop4":"value",  
      "prop5":"value",  
      "obj4" : {  
        "prop6":"value",  
        "prop7":"value",  
        "arr"  :["val1", "val2"]  
      }  
    }  
  }  
}  

Code I tried but at line 8 unable to get the hierarchy

var input = "nested array as above";  
var output = {};  
var globalTemp = output;  
for(var i = 0 ; i<input.length ; i++){  
  var tempObj = input[i];  
  for(var key in tempObj){  
    if(key == "hierarchy"){     
      globalTemp = globlalTemp[tempObj[key]] = {};  
    }  
  }  
}  
console.log(globalTemp);
pjay
  • 385
  • 1
  • 3
  • 16

2 Answers2

2

You can use forEach and reduce methods and inside create shallow copy of current object and delete hierarchy property.

const data = [{"hierarchy":["obj1"],"prop1":"value"},{"hierarchy":["obj1","obj2"],"prop2":"value","prop3":"value"},{"hierarchy":["obj1","obj3"],"prop4":"value","prop5":"value"},{"hierarchy":["obj1","obj3","obj4"],"prop6":"value","prop7":"value","arr":["val1","val2"]}]

const result = {}
data.forEach(function(o) {
  o.hierarchy.reduce(function(r, e) {
    const clone = Object.assign({}, o);
    delete clone.hierarchy
    return r[e] = (r[e] || clone)
  }, result)
})

console.log(result)
Nenad Vracar
  • 102,378
  • 14
  • 116
  • 136
  • Can you please explain this code, it will be very helpful. Treat me as newbee – pjay Mar 15 '18 at 20:53
  • Hey nenad, I've gone through reduce method, pretty much understood code. Can you give some pointers for reverse conversion(nested obj to arr of obj). – pjay Mar 16 '18 at 05:45
1

With a newer version of javascript, you could use restparameters for the wanted value key/value pairs and build a nested structure by iterating the given hierarchy property by saving the last property for assigning the rest properties.

The reclaimed part getFlat uses an array as stack without recursive calls to prevent a depth first search which tries to get the most depth nodes first.

At start, the stack is an array with an array of the actual object and another object with an empty hierarchy property with an empty array, because actually no key of the object is known.

Then a while loop checks if the stack has some items and if so, it takes the first item of the stack and takes a destructuring assignment for getting an object o for getting back all key/value pairs and another object temp with a single property hierarchy with an array of the path to the object o.

The push flag is set to false, because only found properties should be pushed later to the result set.

Now all properties of the object are checked and if

  • the value is truthy (to prevent null values),
  • the type is an object (null is an object) and
  • the property is not an array

then a new object is found to inspect. This object is pushed to the stack with the actual path to it.

If not, then a value is found. This key/value pair is added to the temp object and the flag is set to true, for later pushing to the result set.

Proceed with the keys of the object.

Later check push and push temp object with hierarchy property and custom properties to the result set.

function getFlat(object) {
    var stack = [[object, { hierarchy: [] }]],
        result = [],
        temp, o, push;

    while (stack.length) {
        [o, temp] = stack.shift();
        push = false;
        Object.keys(o).forEach(k => {
            if (o[k] && typeof o[k] === 'object' && !Array.isArray(o[k])) {
                stack.push([o[k], { hierarchy: temp.hierarchy.concat(k) }]);
            } else {
                temp[k] = o[k];
                push = true;
            }
        });
        push && result.push(temp);
    }
    return result;
}

var data = [{ hierarchy: ["obj1"], prop1: "value" }, { hierarchy: ["obj1", "obj2"], prop2: "value", prop3: "value" }, { hierarchy: ["obj1", "obj3"], prop4: "value", prop5: "value" }, { hierarchy: ["obj1", "obj3", "obj4"], prop6: "value", prop7: "value", arr: ["val1", "val2"] }],
    object = data.reduce((r, { hierarchy, ...rest }) => {
        var last = hierarchy.pop();
        hierarchy.reduce((o, k) => o[k] = o[k] || {}, r)[last] = rest;
        return r;
    }, {}),
    reclaimedData = getFlat(object);

console.log(object);
console.log(reclaimedData);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 323,592
  • 20
  • 270
  • 324
  • Nina thanks for the reply, I'm trying to understand "getflat" function. Could you please explain the code if possible. please tell me how did you approach this problem. – pjay Mar 16 '18 at 08:36
  • what do you mean with *"how did you approach this problem"*? actually i wrote a recursive function and then i found a wrong order (read: different than the given) and wrote another function without recursive parts. – Nina Scholz Mar 16 '18 at 08:39
  • I mean the approach is very nice, I never did like this. I just wanted to understand how did you break the problem and solved it with only few lines. Thankyou – pjay Mar 16 '18 at 10:02
  • it's an iterative process to think about some approaches. but you have to iterate the keys of the object and look if nested objects exists, that is the frame. the consiteration of a stack based approach vs an recursive approach come from a try out and a check if the result matches the wanted result. by recursive approach, the first key is pushed at last to the result array, but with a breadth-first search, you get the wanted result. – Nina Scholz Mar 16 '18 at 10:12