I have an object like this:
var data = {"prop.health": 1, "prop.cost":1, "prop.time":1}
I want to change it into an object like this:
{
"prop": {
"health": 1,
"cost":1,
"time":1
}
}
Here's my code:
_.each(data, function (value, key) {
var split = key.split('.')
if (split.length > 1) {
data[split[0]] = data[split[0]] || {}
data[split[0]][split[1]] = value
delete data[key]
}
})
But this only works for 1 level of nesting. How would you write it to ensure it works for as deeply nested properties as you need?
I have an object like this:
var data = {"prop.health": 1, "prop.cost":1, "prop.time":1}
I want to change it into an object like this:
{
"prop": {
"health": 1,
"cost":1,
"time":1
}
}
Here's my code:
_.each(data, function (value, key) {
var split = key.split('.')
if (split.length > 1) {
data[split[0]] = data[split[0]] || {}
data[split[0]][split[1]] = value
delete data[key]
}
})
But this only works for 1 level of nesting. How would you write it to ensure it works for as deeply nested properties as you need?
Share Improve this question edited Nov 12, 2015 at 1:02 Harry asked Nov 12, 2015 at 0:54 HarryHarry 55.1k76 gold badges187 silver badges270 bronze badges 8-
2
How does nested look?
prop.test.fun
?? – epascarello Commented Nov 12, 2015 at 0:56 -
1
@epascarello
{'prop':{'test': {'fun': 1}}}
– Harry Commented Nov 12, 2015 at 1:01 - Is that underscore or lodash you are using? – AtheistP3ace Commented Nov 12, 2015 at 1:01
- @AtheistP3ace lodash – Harry Commented Nov 12, 2015 at 1:01
- 2 @RensTillmann I've used to before to keep client side view models synced with a server side object and just had it pass the object path and value down to me and from that server side path update my client side view model. – AtheistP3ace Commented Nov 12, 2015 at 1:09
3 Answers
Reset to default 8You can use a bination of _.transform
and _.set
, for example
data = _.transform(data, function(transformed, val, key) {
_.set(transformed, key, val);
});
Results in
{"prop":{"health":1,"cost":1,"time":1}}
Without a library it would be something like this:
(function(){
var data = {"prop.health": 1, "prop.cost":1, "prop.time":1, "prop.test.fun" : 1, "prop.test.sun" : 1};
var obj = {}; //will hold the object all parsed out
Object.keys(data).forEach( function (key) { //loop through the keys in the object
var val = data[key]; //grab the value of this key
var step = obj; //reference the object that holds the values
key.split(".").forEach(function(part, index, arr){ //split the parts and loop
if(index===arr.length-1){ //If we are at the last index, than we set the value
step[part] = val;
} else if(step[part]===undefined) { //If we have not seen this key before, create an object
step[part] = {};
}
step = step[part]; //Step up the object we are referencing
});
} );
console.log(obj);
}());
Or the double reduce loop
(function(){
var data = {"prop.health": 1, "prop.cost":1, "prop.time":1, "prop.test.fun" : 1, "prop.test.sun" : 1};
var result = Object.keys(data).reduce( function (obj, key) { //loop through the keys in the object
var val = data[key]; //grab the value of this key
key.split(".").reduce(function(step, part, index, arr){ //split the parts and loop
if(index===arr.length-1){ //If we are at the last index, than we set the value
step[part] = val;
} else if(step[part]===undefined) { //If we have not seen this key before, create an object
step[part] = {};
}
return step[part]; //Step up the object we are referencing
}, obj);
return obj;
}, {});
console.log(result);
}());
Depending on a number of factors (e.g. if the original object always has keys you want to delete, etc.) you may be able to use _.set
:
var data = {"prop.health": 1, "prop.cost":1, "prop.time":1};
_.each(data, function (value, key) {
delete data[key];
_.set(data, key, value);
});
_.set
will create the path if it doesn't exist. The above results in:
{"prop":{"health":1,"cost":1,"time":1}}
And {"prop.health": 1, "prop.cost.food":1, "prop.time":1}
will result in:
{"prop":{"health":1,"cost":{"food":1},"time":1}}