Parse 2 dimensional JSON array in Javascript - javascript

I have a two dimensional JSON array where each element contains several attributes. The example below is intentionally simplified:
var map_data = { "1":
{"1":{"name":"aa"},"2":{"name":"bb"}},
"2":
{"1":{"name":"cc"},"2":{"name":"dd"}}
};
I try to parse the data but .length doesn't work:
for(x=1; x<=map_data.length; x++) {
for(y=1; y<=map_data[x].length; y++) {
// CODE
}
}
Many, many thanks!

That's not an array, they are simple objects, that's why you cannot use the length property.
You need to use the for...in statement:
for(var x in map_data) {
if (map_data.hasOwnProperty(x))
for(var y in map_data[x]) {
if (map_data[x].hasOwnProperty(y)) {
// CODE
}
}
}
The hasOwnProperty checks are because this statement iterates over all properties, inherited or not, and if something (like some JavaScript frameworks) augmented the Array.prototype or Object.prototype objects, those augmented properties will be also iterated.
You should know that this statement doesn't ensure anyhow the order of iteration.
I would recommend you to use a "real" array:
[
[{"name":"aa"},{"name":"bb"}],
[{"name":"cc"},{"name":"dd"}]
]
In this way you will be able to use the length property to iterate over the indexes.

hasOwnProperty is used to determine whether an object has the specified property as a direct property of that object with no respect to it's prototype chain.
for(var i in map_data){
if(map_data.hasOwnProperty(i)){
for(var j in map_data[i]){
if(map_data[i].hasOwnProperty(j)){
/*do whatever you want with map_data[i][j]*/
}
}
}
}

Since map_data is an object instead of an array you need to use for/in loop:
for (var x in map_data) {
// check for hasOwnProperty omitted for simplicity.
for (var y in map_data[x]) {
// CODE.
}
}
But it's better to send that JSON as an array [a,b,c] instead of an object {"0":a,"1":b,"2":c}.

Use the for .. in construct:
for (var m in map_data) {
// ...
}
Also, I must note that this isn't a "JSON array", but rather a nested object. JSON is just the string representation of nested JS objects and arrays.

if it helps someone, its a example of c# and javascript:
c#:
List<List<string>> list_array = new List<List<string>>();
JavaScriptSerializer jss = new JavaScriptSerializer();
string _myJSONstring = jss.Serialize(list_array);
/*in this case list_array is a list bidimensional, but can be a single array,
if you print _myJSONstring, this will show like this: "[["XX","AAAA"],["YY","BBBB"]]" */
javascript:
into a function that get the string from c#:
var a = JSON.parse(array);
for (var t = 0; t < array.length; t++) {
for (v = 0; v < array[t].length; v++) {
alert(array[t][v]);
}
}

Related

Unwrap objects in array

I have an array of objects:
var Props = [booleanPoint, buttonPoint, checkboxPoint, datePoint, dialPoint, gaugePoint,
groupboxPoint, htmlPoint, imagePoint, livetextPoint, livetrendsPoint, permissionsPoint,
rangePoint, selectPoint, spectrumPoint];
Console log shows:
Edited:
I want to extract the properties inside each object. How do I do it?
To be clear I just want the first property in the array, so that I can do Props.booleanPoint, Props.buttonPoint etc.
You question is not very clear, but I guess you're trying to extract the first (and only) property from each object in the list, whose name you don't know.
If yes, consider this:
extracted = Props.map(function(obj) {
for(var p in obj)
return obj[p];
});
If you want to combine all properties into one big object, try this:
allProps = Object.assign.apply(null, Props)
I'm not sure exactly what result you're after, but the best solution is probably either a forEach or a map.
var properties = {};
Props.forEach(function(object) {
// update properties somehow based on object
});
or
var properties = Props.map(function(object) {
return [some property of object];
});
The first just runs some code on each entry in the array; the second returns a new array with the results of that code.
Otherwise, the classic for loop works too:
var properties = {};
for (var i = 0; i < Props.length; i++ {
// update properties somehow based on Props[i]
}

When extending Array in Javascript, why does this.length mismatch with this' content?

Say I want to extend Array with a to_html() method:
Array.prototype.to_html = function() {
console.log(this.length);
for(var i in this) {
console.log(this[i]);
}
};
And I have an array:
var arr = [1, 2, 3];
When calling arr.to_html(), the first line in console looks fine:
3
So far so good. But here are the following lines:
1
2
3
function() {
console.log(this.length);
for(var i in this) {
console.log(this[i]);
}
}
Oops, where does the fourth element come from? How can I get rid of it?
Try this instead to ensure you only iterate over the array items
for(var i = 0; i < this.length; i++) {
console.log(this[i]);
}
for in will iterate all properties on the object. It is including the property/method you defined on the prototype as well
Javascript for-in loops get all the properties of an object. But Arrays have properties that don't come from the numerical indexes. Try printing i along with this[i]. You'll see at least one string-named property.
For most of the time, it is more desirable to use hasOwnProperty to avoid looking up the prototype chain. The following code should get you the expected results.
for (var i in this) {
if (this.hasOwnProperty(i)) {
console.log(this[i]);
}
}

How does for(var x in object) work if there is initially no var x in the object, initially?

I have an object, and I'm trying to see what's inside of it. So, I used print(object), which should possibly contain Spot: True, indicating that the cat Spot is alive. It returned [object object]. So, I tried, show(object), and I got Spot: True. I think that's right, but I'm not sure what the indexes are like. For example, I'm not sure if the keys are associative or numeric, or even if associative arrays are allowed in JavaScipt.
The reason I wonder why is because for (var cats in object){show(cats);} returns Spot. I can't find a way to locate the string 'cat' as being part of the array.
The cats in your example is a new variable that holds each object of iteration.
And yes, "associative arrays" are allowed, but they're really just objects:
var foo = {
bar: "baz"
}
alert(foo.bar);
alert(foo["bar"]);
Re: the for/in statement: it's more or less the same as the following, here using an array:
var cats;
var arr = [42, 69];
for (var i = 0; i < arr.length; i++) {
cats = arr[i];
alert(cats);
}
Or you can use for/in and it becomes:
for (cats in arr) {
alert(arr[cats]);
}
It's slightly different for arrays, but there's no "cats" in the array, either.
Fiddle
Javascript has arrays and objects. Arrays have numeric continuous indexes [0..length) and ordered while objects can have random indexes (strings, numbers) and are not necessarily ordered (depends on the implementation).
Using for(var key in obj) {} should only be used for objects and iterates over the properties the object has. You can use obj[var] to access the value of each property.
Note that it's useful to add an if(!obj.hasOwnProperty(key)) continue; check to the loop to ensure you do not hit properties introduced in the object's prototype.
If object is your object, I'm guessing it's not actually an array. The for (var x in object) could also be enumerating the elements (properties, functions, etc.) of your object.
Where does your object come from? What are show() and print()?
If I was trying to print out the properties of an object I might have something like this:
var myObject = {
property1: 'Test',
property2: 'Test2',
function1: function() {
// do something
}
};
for (var prop in myObject) {
if (myObject.hasOwnProperty(prop)) {
console.log(prop + ' = ' + myObject[prop]);
}
}
This should output the following:
property1 = Test
property2 = Test2
function1 = function() { // do something }
Here's a jsFiddle to show the example.
With that said, JavaScript doesn't really have associative arrays. What you can have is an object with property:value pairs, which is what I think you have.

Why for-in iterates through array methods also?

on a page I use similar syntax to google analitycs code, to pass parameters to another script. I iterate through the array and try to construct query part of URL according to the parameters in the included script.
The problem is the following iterates through the javascript array objects methods also and mess up resulting queryString.
index.html:
<script>
var params = [];
params['first'] = '1';
params['second'] = '2';
(function() {
var vs = document.createElement('script');
vs.async = true; vs.type = 'text/javascript';
vs.src = 'http://my.domain.com/js/includedScript.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(vs, s);
})();
</script>
includedScript.js:
function(paramsArray) {
tmpArray = [];
for(i in paramsArray) {
tmpArray.push(i + '=' + escape(paramsArray[i]));
}
var queryString = tmpArray.join('&');
}(params);
I got (shortened):
queryString == 'first=1&second=2&push&$family=function%20%28%29%20%7B%0A%20%20%20%20return%20lower%3B%0A%7D&$constructor=function%20Array%28%29%20%7B%0A%20%20%20%20%5Bnative%20code%5D%0A%7D&pop=function%20pop%28%29%20%7B%0A%20%20%20%20%5Bnative%20code%5D%0A%7D&push=function%20push%28%29%20%7B%0A%'
I expect:
queryString == 'first=1&second=2'
It's strange, that on my localhost blank page it's working well. Could some other javascript on the index.html page collide with my code? How can I fix the collision by changing only my code (preferably only the includedScript.js file)?
Thanks in advance.
One small change:
var params = {}; // notice the difference here!
params['first'] = '1';
params['second'] = '2';
and another one here
for(i in paramsArray) {
if(paramsArray.hasOwnProperty(i)){
tmpArray.push(i + '=' + escape(paramsArray[i]));
}
}
JavaScript's Array should only be used with numeric indexes. For associative arrays use Object instead. Also to make sure that the properties you get were added by you and do not belong to the a prototype use hasOwnProperty.
See the documentation on mozilla.org for more info.
An array is an ordered set of values
associated with a single variable
name. Note that you shouldn't use it
as an associative array, use Object
instead.
Also you could read this article:
http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/
Note: The for ... in JavaScript construct has no connection with Array. Its purpose is to iterate over Object properties, not Array elements. In JavaScript properties also include methods.
Fun with JavaScript.
Try the following code and tell me if you're surprised:
var x = [];
x['one'] = 1;
x['one'] = 2;
alert(x.length);
then try this one:
Object.prototype.myProp = 123;
var x = {one: 1, two: 2}
for(var prop in x){
alert(x[prop]);
}
You want to do this
for (i in paramsArray) {
if (paramsArray.hasOwnProperty(i)) {
....
}
}
You should not use for..in to iterate through array elements. Things can be prototyped onto an object automatically to make use of DOM methods or programatically by other javascript on a page (like prototyping).
You should instead get a count of array elements using .length and a normal for loop.
var l = paramsArray.length;
for (var c = 0; c < l; c++) {
// do stuff
}
duncan's answer is correct, and that is because the for-in loop treats the paramsArray as an object, not an array.
And as Alin mentioned, use for (var i = 0; i < paramsArray.length; i++) for arrays.
This is usually an issue when looping using for...in, which is never really recommended.
A way around it is to use the .hasOwnProperty() method to ensure you are getting your own variables:
for (var k in foo) {
if (foo.hasOwnProperty(k)) {
// do something with foo[k]
}
}
Or as others have suggested, use a regular for loop:
for(var k = foo.lenght-1; k >= 0; --k) {
// do something with foo[k]
}
Which is more efficient (especially when reversed)
I love Array.forEach(). It takes a function as an argument. That function receives the element, index, and original list as arguments.
["a","b","c"].forEach(function(item, index, list)
{
console.log("the item at index " + index + " is " + item);
});
To make it compatible with older versions of IE, see here.

Iterate over defined elements of a JS array

I'm using a JS array to Map IDs to actual elements, i.e. a key-value store. I would like to iterate over all elements. I tried several methods, but all have its caveats:
for (var item in map) {...}
Does iterates over all properties of the array, therefore it will include also functions and extensions to Array.prototype. For example someone dropping in the Prototype library in the future will brake existing code.
var length = map.lenth;
for (var i = 0; i < length; i++) {
var item = map[i];
...
}
does work but just like
$.each(map, function(index, item) {...});
They iterate over the whole range of indexes 0..max(id) which has horrible drawbacks:
var x = [];
x[1]=1;
x[10]=10;
$.each(x, function(i,v) {console.log(i+": "+v);});
0: undefined
1: 1
2: undefined
3: undefined
4: undefined
5: undefined
6: undefined
7: undefined
8: undefined
9: undefined
10: 10
Of course my IDs wont resemble a continuous sequence either. Moreover there can be huge gaps between them so skipping undefined in the latter case is unacceptable for performance reasons. How is it possible to safely iterate over only the defined elements of an array (in a way that works in all browsers and IE)?
Use hasOwnProperty within for ... in to make sure that prototype additions aren't included:
for (var item in map)
if (map.hasOwnProperty(item)) {
// do something
}
There are three issues:
You should not use for...in to iterate arrays.
You are using the wrong data type for your requirements.
You are not using for...in correctly.
If you want to have something like a hash table then use a plain object:
var map = {};
map[123] = 'something';
map.foo = 'bar';
// same as map['foo'] = 'bar';
//...
It looks like an array, but it is not. It is an object with property 123. You can use either dot notation obj.key (only if the key is a valid identifier - 123 would not be valid so you have to use the following notation) or array notation obj['key'] to access object properties.
It seems that an object would be a more appropriate data structure.
But even then you should make a call to hasOwnProperty (every time you use for...in):
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
//do something
}
}
This checks whether a property is inherited from the prototype (it will return false then) or is truly an own property.
Use the EcmaScript 5 builtin Object.keys, and on non ES5 browsers, define it thus:
Object.keys = function (o) {
var keys = [];
var hasOwnProp = Object.prototype.hasOwnProperty;
if (Object.prototype.toString.call(o) === '[object Array]') {
for (var k in o) {
if (+k === (k & 0x7fffffff) && hasOwnProp.call(o, k)) {
keys[keys.length] = k;
}
}
keys.sort(keys, function (a, b) { return a - b; });
} else {
for (var k in o) {
if (hasOwnProp.call(o, k)) {
keys[keys.length] = k;
}
}
}
return keys;
};
1) use an object like already suggested, it is by far the best solution.
2) if you for some reason need to use an array - don't be scared looping over it with
for(var i, len = arr.length;len < i;i++)
it's very very fast.
3) don't use $.each or similar methods if you want performance - they create a new callstack for every iteration, which is a huge overhead.
Don't use an array. Use an object hash instead
var map = {};
map[key] = value;
...
for (var key in map) {
do something to map[key]
}
You can't do a lot without actually doing a check to see if the value is undefined and then doing operation a or operation b. It would be better to use a predicate to determine if the value is undefined:
x = $.grep(x, function(v, i) { return (typeof(v) != "undefined"); });
There isn't. The only way would be to omit the items from the collection completely, any solution you come up with would still have to do a test on each element for the value.
You could come up with different methods of adding the items key/value to object literals or what have you, but you would still need to omit undefined entries if you do not wish to enumerate over them.

Categories

Resources