How can I get a value from a nested object, using an array of keys?
// my sample object
var obj = {
type : "Purchase",
category : "Apartment",
categoryOptions : {
apartment : {
floors : {
type : "number",
value : null,
placeholder : "Total Floors"
},
},
},
}
var keysArray = ["value", "floors", "apartment", "categoryOptions"]
I tried to use array.reduceRight to achieve this but could not make it work.
here is what I've tried :
var roadToValue = keysArray.reduceRight(
function(previousValue, currentValue){
return previousValue + "[" + currentValue + "]" ;
}
);
// above function results in a single string like
// "categoryOptions[apartment][floors][value]"
// which off-course can't be used as object key
// and obj[roadToValue] results in 'undefined'
is there any way so I can get the proper key to pass to obj here?
You definitely can use reduceRight for this. The problem is that you created a string, however you need to pass your object as initialValue and use the squared bracket notation:
var obj = {"type":"Purchase","category":"Apartment","categoryOptions":{"apartment":{"floors":{"type":"number","value":null,"placeholder":"Total Floors"}}}}
var keysArray = ["value", "floors", "apartment", "categoryOptions"]
var value = keysArray.reduceRight((r, e) => r[e] || r, obj)
console.log(value)
Related
Here I want to read key name of obj.
Like "CIRTGroupBox1", "CIRTGroupBox2"
Try this :
var arr = [{
'CIRTGroupBox1': ''
}, {
'CIRTGroupBox2': ''
}, {
'CIRTGroupBox3': ''
}];
// Using array.map() method
var usingMapKeys = arr.map((obj) => Object.keys(obj)[0]);
// Using Object.entries() method
var usingEnteriesKeys = arr.map((obj) => Object.entries(obj)[0][0]);
console.log(usingMapKeys);
console.log(usingEnteriesKeys);
is it?
var x = {
"ob1": "value",
"ob2": {
"ob21": "value"
}
};
var keys = Object.keys(x);
console.log(keys);
You can do that using Object.keys method in JS like below
var keys = Object.keys(groupBoxesTemp);
This will return string array and each item in it is the key of this object.
If you want to read values pertaining those 2 keys, you can do like below using the for-in loop:
for(item in groupBoxesTemp){
console.log('key is: ', item);
console.log('value is: ', groupBoxesTemp[item]);
}
Based on your screenshot, temp is an array of objects which has 3 objects in it. You can do that too like below:
temp.forEach(function(item, index){
//key for all objects in the array will be logged.
console.log( Object.keys(item) );
});
I have an object that looks like this:
var someUglyObject =
{
"1-1" : {foo1: "foo1-1Value", bar1: "bar1-1value"},
"1-2" : {foo2: "foo1-2Value", bar2: "bar1-2value"},
"2-1" : {foo2: "foo2-1Value", bar2: "bar2-1value"},
"2-2" : {foo2: "foo2-2Value", bar2: "bar2-2value"}
}
I need to simplify the nested object above and convert into a simpler object after some processing (concatenation) like below:
var myObj = {
"1": { propsTogether : "foo1-1Valuebar1-1valuefoo1-2Valuebar1-2value"},
"2": { propsTogether : "foo2-1Valuebar2-1valuefoo2-2Valuebar2-2value" }
}
My plan is to interate through the keys like this, but not sure how to group the props together based on the first char of the key , i.e. for a key with value of '2-1' - 2 should be the new key.
var myObj= {};
Object.keys(someUglyObject).forEach(function(key) {
}
You can use Object.keys and reudce
Here idea is
First get the keys out of object.
Sort them // Object don't have order
Now split key on - and use first element as key on op object.
Use object.values and join them in desired format and place it on respective key
var obj = {'1-1' : {foo1: "foo1-1Value", bar1: "bar1-1value"},'1-2' : {foo2: "foo1-2Value", bar2: "bar1-2value"},'2-1' : {foo2: "foo2-1Value", bar2: "bar2-1value"},'2-2' : {foo2: "foo2-2Value", bar2: "bar2-2value"}}
let op = Object.keys(obj).sort().reduce((op,inp)=>{
let key = inp.split('-',1)[0]
op[key] = op[key] || {props:''}
op[key].props = op[key].props + Object.values(obj[inp]).join('')
return op
},{})
console.log(op)
I have a json, it is
{
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.sub1.sub2": "content4"
}
I want to recovery the structure, like
{
"prop1": {
"sub1": {
"sub2" : "content1",
"sub3" : "content2"
}
},
"prop2": {
"sub1": {
"sub2" : "content3"
}
},
"prop3": {
"sub1": {
"sub2" : "content4"
}
}
}
I split the key with dot to get each key.
for (var key in json) {
var keySplit = key.split('.');
// Todo: recovery the structure
}
But not found a good solution.
Is anyone has solution?
You can use Array#reduce method.
var obj = {
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.sub1.sub2": "content4"
};
// iterate over the property names
Object.keys(obj).forEach(function(k) {
// slip the property value based on `.`
var prop = k.split('.');
// get the last value fom array
var last = prop.pop();
// iterate over the remaining array value
// and define the object if not already defined
prop.reduce(function(o, key) {
// define the object if not defined and return
return o[key] = o[key] || {};
// set initial value as object
// and set the property value
}, obj)[last] = obj[k];
// delete the original property from object
delete obj[k];
});
console.log(obj);
Answer by Pranav C Balan is right for the question you asked. But JSON's might not be as simple as you have mentioned above and can have array's also and few keys might not have "." in them. To handle all these cases you can use the following one.
var obj = {
"prop1.sub1.sub2": "content1",
"prop1.sub1.sub3": "content2",
"prop2.sub1.sub2": "content3",
"prop3.0.sub2": "content4"
};
function createJSONStructure(obj) {
Object.keys(obj).forEach(function(k) {
var prop = k.split('.'); //split on . to get elements
if(prop.length >1){ //If there is no dot just key the value as is.
let data = obj;//Copy the default object to data in each loop
for(i=0;i<prop.length-1;i++){
if(data[prop[i]]){ // Check if the key exists
if((prop[i+1].match(/^\d+$/) && !Array.isArray(data[prop[i]])) // Check if the next key is a digit and the object we have is a JSON
|| (!prop[i+1].match(/^\d+$/) && Array.isArray(data[prop[i]]))){ // Check if the next key is not a digit and the object we have is a Array
throw new Error("Invalid header data"); //If any of the above cases satisfy we cannot add the key so we can throw an error.
}
data = data[prop[i]]; // If key exisits make the data variable as the value of the key
}else {
if(prop[i+1].match(/^\d+$/)){ //If the key is not available see if the next parameter is a digit or string to decide if its array or string
data[prop[i]] = [];
}else{
data[prop[i]] = {};
}
data = data[prop[i]]; //Assign this new object to data
}
};
data[prop[i]] = obj[k]; //Finally add the value to final key
delete obj[k]; // delete the exisiting key value
}
});
return obj;
}
console.log(createJSONStructure(obj));
I have an js object like
{
a: 1,
b: 2,
c: 3
}
I wanted to stringify the above object using JSON.stringify with the same order. That means, the stringify should return me the strings as below,
"{"a":"1", "b":"2", "c":"3"}"
But it is returning me like the below one if my js object has too many properties say more than 500,
"{"b":"2", "a":"1", "c":"3"}"
Is there any option to get my js object's json string as in sorted in asc.
If the order is important for you, don't use JSON.stringify because the order is not safe using it, you can create your JSON stringify using javascript, to deal with string values we have 2 different ways, first to do it using regexp an replace invalid characters or using JSON.stringify for our values, for instance if we have a string like 'abc\d"efg', we can simply get the proper result JSON.stringify('abc\d"efg'), because the whole idea of this function is to stringify in a right order:
function sort_stringify(obj){
var sortedKeys = Object.keys(obj).sort();
var arr = [];
for(var i=0;i<sortedKeys.length;i++){
var key = sortedKeys[i];
var value = obj[key];
key = JSON.stringify(key);
value = JSON.stringify(value);
arr.push(key + ':' + value);
}
return "{" + arr.join(",\n\r") + "}";
}
var jsonString = sort_stringify(yourObj);
If we wanted to do this not using JSON.stringify to parse the keys and values, the solution would be like:
function sort_stringify(obj){
var sortedKeys = Object.keys(obj).sort();
var arr = [];
for(var i=0;i<sortedKeys.length;i++){
var key = sortedKeys[i];
var value = obj[key];
key = key.replace(/"/g, '\\"');
if(typeof value != "object")
value = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
arr.push('"' + key + '":"' + value + '"');
}
return "{" + arr.join(",\n\r") + "}";
}
The JavaScript objects are unordered by definition (you may refer to ECMAScript Language Specification under section 8.6, click here for details ).
The language specification doesn't even guarantee that, if you iterate over the properties of an object twice in succession, they'll come out in the same order the second time.
If you still required sorting, convert the object into Array apply any sorting algorithm on it and then do JSON.stringify() on sorted array.
Lets have an example below as:
var data = {
one: {
rank: 5
},
two: {
rank: 2
},
three: {
rank: 8
}
};
var arr = [];
Push into array and apply sort on it as :
var mappedHash = Object.keys( data ).sort(function( a, b ) {
return data[ a ].rank - data[ b ].rank;
}).map(function( sortedKey ) {
return data[ sortedKey ];
});
And then apply JSON.stringy :
var expectedJSON = JSON.stringify(mappedHash);
The output will be:
"[{"rank":2},{"rank":5},{"rank":8}]"
I was working on a solution to another question posed, and I came up with a solution, but I'm convinced that there's a more elegant way to do it. Let's say that you have an object where all of the values are a string of values separate by commas, like this:
{ "action" : "goto,goto", "target" : "http://www.google.com,http://www.cnn.com" }
But, you'd like to separate the values and break up the object into an array of objects, like this:
[
{ "action" : "goto", "target" : "http://www.google.com" },
{ "action" : "goto", "target" : "http://www.cnn.com" }
]
Here's what my solution was:
var actions = obj.action.split(',');
var targets = obj.target.split(',');
// combined the actions and targets arrays
var combinedData = _.zip(actions, targets);
// go through the combinedData array and create an object with the correct keys
var commandList = _.map(combinedData, function(value) {
return _.object(["action", "target"], value)
});
This does what I want and doesn't look terrible, but is there a slicker way of accomplishing this?
Functional style is great. Here's a more direct approach.
var newObjects = [];
for(var k in o) {
var vals = o[k].split(',');
for(var i = 0, len = vals.length; i < len; i++) {
newObjects[i] = newObjects[i] || {};
newObjects[i][k] = vals[i];
}
}
I wouldn't worry too much about the implementation until you come up with a nice, compact, semantic name for this operation. Any ideas?
So, I did a little refactoring of my code to create a more functional and cleaner looking answer:
var obj = { "action" : "goto,goto", "target" : "http://www.google.com,http://www.cnn.com" }
// separate and split the values form the object
function separate(obj) {
return _.map( _.values( obj ), function(value) {
return value.split(',');
});
}
// returns [[ "goto", "goto"], ["http://www.google.com", "http://www.cnn.com"]]
// call separate and recombine the values with zip
function separateAndRecombine(obj) {
return _.zip.apply(_, separate(obj));
}
// returns [[ "goto", "http://www.google.com"], ["goto", "http://www.cnn.com"]]
// accept an object that has properties with a string of values
// separated by commas, and separate the values to create an array of objects
function unwind(obj) {
return _.map( separateAndRecombine(obj), function(value) {
return _.object(_.keys(obj), value)
});
};
/* returns:
[{ "action" : "goto", "target" : "http://www.google.com" },
{ "action" : "goto", "target" : "http://www.cnn.com" }] */
Now, unwind() will take an object with any number of properties or values and 'unwind' all of the existing properties.