JSON.stringify(object) incorrect - javascript

Sorry for my last question being so confusing, I was confused my self, but now I got a proper example:
var obj = {};
obj.entities = [];
obj.entities["player"] = [];
obj.entities["player"]["0"] = [];
obj.entities["player"]["0"]["pos"] = "0,0";
var jsonStr = JSON.stringify(jsonObj);
// {"entities":[]}
console.log(JSON.stringify(obj));
The output of JSON.stringify(obj) is wrong as you can see.
What causes this ?

You're first building an array ([]), then assigning properties to it with non-number keys (player). This is technically possible (as in not causing an error), but it's not what arrays are for.
You should use objects ({}) instead. Also, ["player"] is the same as .player.
var obj = {};
obj.entities = {};
obj.entities.player = []; // array here because you're filling with indices ([0])
obj.entities.player[0] = {}; // object again, because non-indices as keys (`pos`)
obj.entities.player[0].pos = "0,0";
Objects can take any property key. Arrays are a subset of objects, which should only have indices (numbers >= 0) as keys.

Your life would be much easier if you'd define your objects in JSON to begin with:
var obj = {
'entities': [
{'player':{'pos': '0,0'}}
]
};

You're using named array indeces instead of object key/value pairs.
var obj = {};
obj.entities = {};
obj.entities["player"] = {};
obj.entities["player"]["0"] = [];
obj.entities["player"]["pos"] = "0,0";
// {"entities":{"player":{"0":[],"pos":"0,0"}}}
console.log(JSON.stringify(obj));

entities, and entities["player"] and entities["player"]["0"] need to be objects, not arrays.
You're adding properties to these arrays, rather than pushing values onto them. These custom properties are not getting stringified.
The fix is simple:
var obj = {};
obj.entities = {}; // <------------ this is an object now
obj.entities["player"] = {}; // <--------- also an object
obj.entities["player"]["0"] = {}; // <-------- and so on
obj.entities["player"]["0"]["pos"] = "0,0";

I think you have some serious confusions about arrays and objects in javascript. An array ([]) works only with positive integer indexes. In your example you are doing the following:
obj.entities = [];
obj.entities["player"] = [];
You say that obj.entities is an array and then you use player as index. And player is not an integer. So this code makes no sense. On the other hand you could use objects with properties. Those properties can be strings:
obj.entities = {};
obj.entities.player = [];
obj.entities.player[0] = 'foo bar';

You are confusing objects with arrays. The following code will work.
var obj = {};
obj.entities = {};
obj.entities.player = [];
obj.entities.player[0] = {};
obj.entities.player[0].pos = "0,0";
The things you went wrong:
An array can have only integer indexes. So it's incorrect writing a["1"] if you intend to use a as an array.
To be correctly serialized, only an object can have named properties, like object.entities.player or object.entities["player"].

Related

JS- How to convert an array with key and value pairs to an object?

var arr = [];
arr['k1'] = 100;
console.log(arr); //o/p - [k1: 100]
arr.length; //o/p - 0
window.copy(arr); //copies: []
I want to convert this array-like object to a proper obj i.e,
arr = { k1: 100}
So doing window.copy(arr) should copy {k1:100}
NOTE- I need to do this as Node.js express server returns empty arrays in response for such cases.
You can use object spread syntax to copy all own enumerable properties from the original object to a new object:
const arr = [];
arr['k1'] = 100;
const obj = { ...arr };
console.log(obj);
This works even if arr is originally an array, rather than a plain object, because the k1 property exists directly on the array.
(But ideally, one should never have code that assigns to arbitrary properties of an array - better to refactor it to use an object in such a situation to begin with)
var array = []
array["k1"] = 100;
var newObject = Object.assign({},array);
console.log(newObject);

Creating a two-dimensional object from a string of values

In JavaScript, how would I create a two-dimensional object from a string of values, in which the first value would be the name, the last is the content, and all other values in between are properties?
For example, I have a string "capitals,Asia,China,Beijing" and I want the code to split this string into four values and create an object capitals["Asia","China"] = "Beijing";.
How could I do that?
In a complete code piece that would look like this:
<script>
Values = "capitals,Asia,China,Beijing";
Values = Values.split(",");
alert(capitals["Asia","China"]);
</script>
I want the alert box to show me the word Beijing.
How could I do that?
JavaScript does not have two-dimensional arrays or objects that you can access using array[index1, index2] as in some other languages. To do this, you have to use nested objects/arrays, such as
capitals["Asian"]["China"]
To create these, you can do something like:
function makeEntry(obj, str) {
const parts = str.split(','); // array of comma-delimited values
const value = parts.pop(); // final value ("Beijing")
const final = parts.pop(); // final property ("China")
// Find nested property, creating empty object if not there.
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (!(parts in obj)) obj[part] = {};
obj = obj[part];
}
// Set final value.
obj[final] = value;
}
const data = {};
makeEntry(data, "capitals,Asian,China,Beijing");
console.log(data);
console.log(data.capitals["Asian"]["China"]);
This code will work even if there are more levels, such as "capitals,Asia,East Asia,China,Beijing".
Note that there is no way to create a variable in JS given a name. Therefore, we provide an initial object, and build the nest structure within it.
Another approach
Another approach is to create a single-level object with keys such as "capitals,Asian,China". That's easier to create, but might be more inconvenient to access. For example, there would be no easy way to find all the Asian capitals. Below, I'm using regexp to pick apart the input into the first part and the final value.
function makeEntry(obj, str) {
const [, key, value] = str.match(/(.*),([^,]+)$/);
obj[key] = value;
}
const data = {};
makeEntry(data, "capitals,Asian,China,Beijing");
console.log(data);
console.log(data["capitals,Asian,China"]);
You can use WeakMap to set the key of the WeakMap object to an object; Array.prototype.shift(), Array.prototype.splice(), Array.prototype.pop() to set the value of the WeakMap object instance.
let Values = "capitals,Asian,China,Beijing";
Values = Values.split(",");
const capitals = {[Values.shift()]:Values.splice(0, 2)};
const wm = new WeakMap;
wm.set(capitals, Values.pop());
console.log(wm.get(capitals));
You can alternatively set the property of an object to the result of JSON.stringify() called on Values.splice(1, 2)
let Values = "capitals,Asian,China,Beijing";
Values = Values.split(",");
const key = JSON.stringify(Values.splice(1, 2));
console.log(key);
const map = {[Values.shift()]:{[key]:Values.pop()}};
console.log(map.capitals[key]);

Push Duplicate key data on key array in javascript

I have this data structure. I have used the underscorejs but could not find way to that like the below structure
var data = [{"5+":2},{"3-5":0},{"1-3":1},{"0.5":0},{"<30":0},{"5+":1},{"3-5":1},{"1-3":0},{"0.5":0},{"<30":0},{"5+":3},{"3-5":0},{"1-3":3},{"0.5":0},{"<30":0}];
var groupArr = [];
##loop through the data##
data.forEach(function(item){
##find the keys ##
var keys = Object.keys(item);
var obj = {};
obj[keys] = [];
##push the data to object keys array##
obj[keys].push(item[keys])
groupArr.push(obj)
})
By using this data structure I want something like this structure
[{"5+":[2,1,3]},{"3-5":[0,1,0]},{"1-3":[1,0,,3]},{"0.5":[0,0,0]},{"<30":[0,0,0]}]
As I have tried everything but could not find the solution any help would be highly appreciated.
The first part converts the list of objects to a single object, where the keys are each of the unique keys from the list of objects and the values for each key are joined as an array:
{
"5+": [2,1,3],
"3-5": [0,1,0]
...
}
Since this is not the format you wanted, the second part converts this object into a list of objects by looping over each key and creating a new object from it.
var data = [{"5+":2},{"3-5":0},{"1-3":1},{"0.5":0},{"<30":0},{"5+":1},{"3-5":1},{"1-3":0},{"0.5":0},{"<30":0},{"5+":3},{"3-5":0},{"1-3":3},{"0.5":0},{"<30":0}];
// create object with all the values joined together in lists.
var map = data
.reduce(function (map, obj) {
var key = Object.keys(obj)[0];
// checks if the key allready exits in the new object.
// If it does we push a new value into the array,
// otherwise we create a new property with a list with one value.
map[key] ?
map[key].push(obj[key]):
map[key] = [obj[key]];
return map;
}, {});
// convert above result to a list with objects.
var newFormat = Object.keys(map)
.map(function (key) {
var obj = {};
obj[key] = map[key];
return obj;
})
console.log(newFormat)

Length property not updating on object arrays

Two problems consider the following object:
//new obj
var obj = {};
obj['cars'] = [];
obj['cars']['toyota'] = 1;
obj['cars']['mazda'] = 0;
console.log(obj);
console.log(JSON.stringify(obj));
Why does my cars array have length of 0? Do i have to update the length property manually?
Why is my stringified object empty when it has parameters in it i'm assuming it is tied into the length property?
Fiddle:https://jsfiddle.net/wcd7f8Lz/
car is initialized as an array, but used as an Object. and an object does not have length attribute...
To get the length of an object, you can do ̀̀̀̀Object.keys(obj).length (get the keys list, and because it is an array, it have a length).
But the problem is also that you initialize cars as an array, but use it as Object...
see docs here:
http://www.w3schools.com/js/js_arrays.asp
http://www.w3schools.com/js/js_objects.asp
The solution is to initialize it as Object:
//new obj
var obj = {};
obj['cars'] = {}; //And other object
obj['cars']['toyota'] = 1;
obj['cars']['mazda'] = 0;
console.log(obj);
console.log(JSON.stringify(obj));
But if you want instead a simple array:
//new obj
var obj = {};
obj['cars'] = [];
obj['cars'][1] = "toyota";
obj['cars'][0] = "mazda";
console.log(obj);
console.log(JSON.stringify(obj));
The syntax is ̀array[identifier] = value;
(and not ̀̀̀̀̀array[value] = identifier)
I've updated the fiddle.
obj.cars.length is 0, because you don't push new items in array, but change it properties:
var obj = {};
obj.cars = []; // obj.cars is empty array
obj.cars.toyota = 1; // obj.cars is empty array with a new property toyota
obj.cars.push('mazda'); // obj.cars is array with a new property toyota and one element mazda
console.log(obj.cars instanceof Array,
obj.cars.length,
Object.keys(obj.cars)); // output: true 1 ["toyota"]
Why you don't use it in this way?
var cars = [];
cars.push({name:'toyota', value:1});
cars.push({name:'mazda', value:0})
That's because you aren't using an array (despite declaring it with an array literal), you're using it as an object.
Arrays are just a special case of object, meaning they can have individual properties. These properties don't exist "in" the array but instead are properties "of" the array.
var arr = [1, 2, 3];
arr.thing = 'a';
console.log(arr.length); // 3
To add elements to an array, you should use push:
var arr = []; // length: 0
arr.push(1); // length: 1
If you want to be able to access an object both by name and index then you can combine push with custom properties.
var arr = [];
arr.push(0);
arr.mazda = 0;

Javascript: how to dynamically create nested objects INCLUDING ARRAYS using object names given by an array

Very similar to this question:
Javascript: how to dynamically create nested objects using object names given by an array
Instead of calling
assign(obj, keyPath, value)
example of usage of the previously answer:
var accountinfo = {}
assign(accountinfo, ["name", "addressinfo", "zipcode"], "90210");
That will output:
accountinfo = {name: "", addressinfo: {zipcode:"90210"}};
Now, I'd like to support arrays... in the above example, I'd like to support multiple addressinfo per account. I'd like to say:
assign(accountinfo, ["name", "addressinfo[1]", "zipcode"], "90210");
The result would be:
accountinfo = {name: "", addressinfo: [{},{zipcode:"90210"}]}
var regex = /\[([0-9]+)\]/ will show me the # inside the brackets, but I'm not sure how I'd have to iterate through each element in the array to make sure it exists (and create it if it doesn't).. and the difficult part, support this for each array element submitted as part of the function (I'd like to say :
assign(accountinfo, ["family", "name[3]", "addressinfo[1]", "zipcode"], "90210");
Edit:
Figured it out.
function assign(obj, keyPath, value) {
keyPath = keyPath.split(‘.’);
lastKeyIndex = keyPath.length - 1;
var re = /^(.+?)\[*(\d+)*\]*$/;
for (var i = 0; i < lastKeyIndex; i++) {
key = keyPath[i];
var ind;
var middle = re.exec(key);
key = middle[1];
ind = middle[2];
if (ind) {
if (!(obj[key]))
obj[key] = [];
if (!(obj[key][ind]))
obj[key][ind] = {};
}
if (!(key in obj))
obj[key] = {};
if (ind)
obj = obj[key][ind];
else
obj = obj[key];
}
obj[keyPath[lastKeyIndex]] = value;
}

Categories

Resources