snippetjavascriptMinor
Convert flat object keys to hierarchical one
Viewed 0 times
convertflatkeyshierarchicaloneobject
Problem
While responding to a SO question, I wrote the following method to convert a flat key structure to a hierarchical one as given below
In
Out
Converter:
Can this be improved?
Demo: Fiddle
In
{
property1: 'value1',
property2.property3: 'value2',
property2.property7: 'value4',
property4.property5.property6: 'value3',
}Out
{
property1: 'value1',
property2: {
property3: 'value2',
property7: 'value4'
},
property4: {
property5: {
property6: 'value3'
}
}
}Converter:
function convert(obj) {
var res = {}, i, j, splits, ref, key;
for (i in obj) {
if (obj.hasOwnProperty(i)) {
splits = i.split('.');
ref = res;
for (j = 0; j < splits.length; j++) {
key = splits[j];
if (j == splits.length - 1) {
ref[key] = obj[i];
} else {
ref = ref[key] = ref[key] || {};
}
}
};
}
return res;
}Can this be improved?
Demo: Fiddle
Solution
The main complexity of this function arises from using a plain for-in loop to loop over object keys - this adds two extra indentation levels instead of just one level if one were to use a higher-level looping construct. So I would use some library function or create something like:
Within this loop, there's another low-level for-loop, which I would again replace, say... with an
Now, in your code the loop goes over all the parts of the key, checking each time whether it's the last part. Instead of this, I would first remove the last part, loop over all the other parts to ensure all these are initialized, and then simply assign the value to the last position.
With some additional improvements to variable names, I would write it as such:
This code has just 2 levels of nesting compared to the original 4.
function eachKeyValue(obj, fun) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
fun(i, obj[i]);
}
}
}Within this loop, there's another low-level for-loop, which I would again replace, say... with an
Array.forEach method.Now, in your code the loop goes over all the parts of the key, checking each time whether it's the last part. Instead of this, I would first remove the last part, loop over all the other parts to ensure all these are initialized, and then simply assign the value to the last position.
With some additional improvements to variable names, I would write it as such:
function convert(obj) {
var result = {};
eachKeyValue(obj, function(namespace, value) {
var parts = namespace.split(".");
var last = parts.pop();
var node = result;
parts.forEach(function(key) {
node = node[key] = node[key] || {};
});
node[last] = value;
});
return result;
}This code has just 2 levels of nesting compared to the original 4.
Code Snippets
function eachKeyValue(obj, fun) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
fun(i, obj[i]);
}
}
}function convert(obj) {
var result = {};
eachKeyValue(obj, function(namespace, value) {
var parts = namespace.split(".");
var last = parts.pop();
var node = result;
parts.forEach(function(key) {
node = node[key] = node[key] || {};
});
node[last] = value;
});
return result;
}Context
StackExchange Code Review Q#31831, answer score: 3
Revisions (0)
No revisions yet.