JavaScript Multidimensional Arrays [duplicate] - javascript

This question already has answers here:
Is it possible to create an empty multidimensional array in javascript/jquery?
(8 answers)
How can I create a two dimensional array in JavaScript?
(56 answers)
Closed 9 years ago.
This wasn't the question I was going to ask but I have unexpectedly run aground with JavaScript arrays. I come from a PHP background and after looking at a few websites I am none the wiser.
I am trying to create a multi-dimensional array.
var photos = new Array;
var a = 0;
$("#photos img").each(function(i) {
photos[a]["url"] = this.src;
photos[a]["caption"] = this.alt;
photos[a]["background"] = this.css('background-color');
a++;
});
Error message: photos[a] is undefined. How do I do this? Thanks.

JavaScript does not have multidimensional arrays, but arrays of arrays, which can be used in a similar way.
You may want to try the following:
var photos = [];
var a = 0;
$("#photos img").each(function(i) {
photos[a] = [];
photos[a]["url"] = this.src;
photos[a]["caption"] = this.alt;
photos[a]["background"] = this.css('background-color');
a++;
});
Note that you could have used new Array() instead of [], but the latter is generally recommended. Also note that you were missing the parenthesis of new Array() in the first line.
UPDATE: Following from the comments below, in the above example there was no need to use arrays of arrays. An array of objects would have been more appropriate. The code is still valid because arrays are objects in this language, but the following would have been better:
photos[a] = {};
photos[a]["url"] = this.src;
photos[a]["caption"] = this.alt;
photos[a]["background"] = this.css('background-color');

You're trying to assign something to photos[a]["url"], photos[a]["caption"], etc., but photos[a] doesn't exist yet. photos is an empty Array at first, so you have to set photos[a] to something first. Since you want to use string keys ("url", "caption", etc), this something should be a plain object (the javascript equivalent to php associave arrays) (or a Hash if your code base allows it). Then you can use a literal object construct to simplify your function, and Array#push to get rid of the unnecessary a:
var photos = [];
$("#photos img").each(function(img) {
photos.push({
url: img.src,
caption: img.alt,
background: img.style.backgroundColor
});
});
Also, make sure that this is actually your img element. Some each implementations will set this to the global object in your case.
edit: ok, it looks like jQuery.each automatically sets this to the iterated element, but doesn't wrap it in jQuery-goodness, so you have to either wrap this in $() or use plain DOM (I used the latter in my example).
edit2: anyway, using this is kind of strange since the callback function passed to each receives an argument. Might as well use this argument (renamed).

var photos = [];
var imgs = document.getElementById("photos").getElementsByTagName("img");
for(var i=0;i<imgs.length;i++){
photos.push({
src:imgs[i].src,
alt:imgs[i].alt,
background:imgs[i].style.backgroundColor
});
}
That should give you something that is roughly equivalent to this in PHP (I made up pretend data):
Array(
[0] => Array(
"src" => "logo.png",
"alt" => "My Logo!",
"background" => "#ffffff"
)
)
I hope this helps!

When I read this thread I was trying to get an understanding of multidimensional associative arrays. It wasn't clear so I kept researching, this is what I came up with:
var images = new Array;
images['logo'] = { 'src': 'http://example.com/image1.png', 'caption': 'this is the logo', 'background': '#000'};
images['background'] = { 'src': 'http://example.com/image2.png', 'caption': 'this is the background', 'background': '#FFF'};
alert(images['logo']['src']); /* output: http://example.com/image1.png */
alert(images['background']['caption']); /* output: this is the background */
Hope this helps!

multi-dimensional arrays are in these structure:
var photos = new Array();
photos[0] = new Array();
use it as :
photos[0][0] = this.src;
more on JS array here.

Douglas Crockford, of JSLint, would have you create it this way ("Use the array literal notation []"):
var photos = [];
Now remember that you want to create multi-dimensional arrays, which means an array inside an array. This means you need to create the inner-arrays:
$("#photos img").each(function(i) {
photos[a] = []
//continue

Related

Modifying an object causes the modifications to be reflected in a copy of that object previously pushed to an array

I have code similar to the following
var l_mattes_array = [];
var matte_array = [];
var mattes = [];
mattes[0] = "<test><imgsrc>test1</imgsrc></test>";
mattes[1] = "<test><imgsrc>test2</imgsrc></test>";
$(mattes).each(function(i, el)
{
matte_array.imgsrc = ($(el).find("imgsrc").first().text());
l_mattes_array[i] = matte_array;
console.log(l_mattes_array[i]);
});
console.log(l_mattes_array);
The output I am getting is:
[imgsrc: "test1"]
[imgsrc: "test2"]
(2) [Array(0), Array(0)]
0:[imgsrc: "test2"]
1:[imgsrc: "test2"]
The output I want:
[imgsrc: "test1"]
[imgsrc: "test2"]
(2) [Array(0), Array(0)]
0:[imgsrc: "test1"]
1:[imgsrc: "test2"]
The problem is that matte_array is a reference type (all objects are, and arrays are objects, so yes). What this means is, when you say l_matte_array[i] = matte_array, you are actually setting that index of l_matte_array to a reference to the value of the array matte_array, and then when you modify the matte_array again in the second iteration, you are modifying the value referenced by matte_array, that value is the same value that you set l_matte_array[i] to refer to in the preceding iteration.
So all your l_matte_array indices are merely holding a reference to a single shared value, and you have modified that value to have its imgsrc property be equal to "test2".
Go read this MDN article, you will come out of it having a nice understanding of JavaScript datatypes.
Another problem with you code is, you are using an array as an object, which is inappropriate. Use an array if you want to take advantage of its functionality of having numerically indexed elements; if you want to group some properties and/or methods somewhere, just use a normal object (created with a literal: var obj = {}); if you want something to hold a single value, use a variable.
So, I solved your problem in the following way (I am not using a variable for imgsrc because I believe you are modifying the objects that hold imgsrc sometime later in your code, if you are not adding any properties/methods to the objects that you push to l_mattes_array, just replace my object with an imgsrc variable):
var l_mattes_array = [];
var mattes = [];
mattes[0] = "<test><imgsrc>test1</imgsrc></test>";
mattes[1] = "<test><imgsrc>test2</imgsrc></test>";
$(mattes).each(function(i, el) {
var matte_object = {};
matte_object.imgsrc = ($(el).find("imgsrc").first().text());
l_mattes_array[i] = matte_object;
});
console.log(l_mattes_array);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The problem is you're referencing the same object (matte_array), so you're changing the src property but the reference is still the same. What you could to is just initialize matte_array inside the cycle, so each time it becomes a new array, like this:
// ...
// var matte_array = []; // Should not be here
// ...
$(mattes).each(function(i, el)
{
var matte_array = []; // Should be here
// ...
});
// ...
Here you have a working example: https://jsfiddle.net/6j73wgdw/
You can use Array.prototype.map() and remove all html tags with the regular expression /<{1}[^<>]{1,}>{1}/g.
Code:
const mattes = ['<test><imgsrc>test1</imgsrc></test>', '<test><imgsrc>test2</imgsrc></test>'];
const l_mattes_array = mattes.map(el => ({imgsrc: el.replace(/<{1}[^<>]{1,}>{1}/g, '')}));
console.log(l_mattes_array);
I added
matte_array = [];
after adding to l_mattes_array and that fixed it

Named objects and collection of them

not sure how to ask tbh :)
I'm used of PHP's associative arrays so much that I struggle to understand how to create an "named array" of objects.
Example:
I have two arrays, two ints and one boolean. This represents one of my entities. I have multiple entities on which I'm doing some work.
In PHP I would write:
$entitites[$entitity_id]['items'][] = $item;
$entitites[$entitity_id]['items_status'][] = $item_status;
$entitites[$entitity_id]['items_count']++;
and so on..
How do I do this with objects in JS?
var entities = {items:[], items_status: [], items_count: 0};
entities[entity_id].items.push(item)
How does one name his object for later access (via name or in my case, entity_id?)
This code doesnt work for me to this extend that my webpage goes blank without any errors produced :S
I also tried this:
var entities = {};
var entity = {items:[], items_status: [], items_count: 0};
but then I dont know how to always add values to already existing object in entities object and how to call that exact object via name eg. entity_id.
Halp :(
Keep entities as an object. Then you can just go ahead and add each entity_id as a key and an object which has all the details of that entity as the value.
var entities = {};
entities["1234"] = {
"items" : [],
"items_status" : [],
"items_count" : 0
};
There are 2 types involved here: Objects & Arrays.
Arrays are simple and you're probably familiar with them from any other language:
var myArray = []; // this is an empty array
myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 3;
// you could also use "var myArray = [1, 2, 3];" instead
alert(myArray[1]); // alerts the value 2
Note: arrays are actually objects, and can have non-index properties as well
You can also use various array functions such as .push(), .pop(), .shift() and so on to mutate the array instead.
Objects share the square brackets notation, but the purpose is different:
var myObject = {}; // this is an empty object
myObject[0] = 1;
myObject[1] = 2;
myObject[2] = 3;
alert(myObject[1]); // alerts the value 2
// but also...
myObject['prop'] = 4;
alert(myObject['prop']); // alerts the value 4
// and
myObject.prop2 = 5;
alert(myObject.prop2); // alerts the value 5
// and lastly
alert(myObject.prop); // alerts the value 4
So while arrays are accessed by index, objects are accessed by property names.
As for your entities, it looks like an array of objects. Lets see how we can do that:
function Entity() {
this.items = [];
this.items_status = [];
this.items_count = 0;
}
var entitites = [];
entities.push(new Entity());
entities[0].items = [1, 2, 3];
entities[0].items_status = ['good', 'good', 'poor'];
entities[0].items_count = 3;
Or you can wrap insertion in a more elegant function:
Entity.prototype.insert(item, status) {
this.items.push(item);
this.items_status.push(status);
this.items_count++;
}
entities[0].insert(4, 'excellent!');
If you want to keep control of the indexes in your JS array you can do so by not using .push() :
var entities = [];
entities[5] = {items:[], items_status:[], items_count:0};
Just replace 5 by your integer entity_id variable, and there you go.
You can use a regular javascript object to create the associative array you're looking for.
Actually it's PHP's implementation that's abit off but all they do is call it different (associative array) to most other language that simply refer to it as an object or hash.
You can use numeric keys in JS and still access them with the [] square brackets.
It works like this:
var my_obj = {};
my_obj[5] = 'any value';
console.log(my_obj); // {5: 'any value'}
JS will not add any redundant undefined to missing indexes either so when looping over the collection you won't loop over undefined.
Also, I can access the object by using the key as a string or as number so you won't have to check if the key is the right type. Taken from the above example:
console.log(my_obj['5']); // 'any value'
console.log(my_obj[5]); // 'any value'
JS Objects are the equivelant of PHP assoc arrays except JS objects are much more flexible than PHP's associative arrays.
The only downside to this is that you can't have duplicate keys.
No two keys may exist that share the same name, in an array if you .push(an_item) it will create a new index making even a duplicate data entry unique but when overwriting a key with a new value only the last value will persist, mind that :)

Multidimensional keyed array?

I want to create a multidimensional keyed array.
How do I declare the array and then push things in to it?
Is this right?
var galleryData = new Array();
$("#gallery li.gallery-image-item:not(:first)").each(function() {
galleryData.push({comment: 'comment', youTube: 'ODOIUOIhd'});
}
Thanks
That will work. An alternative syntax is
var galleryData = [];
Which is nice because yo can then do something like this:
var superGalleryData = [[],[],[]]; //creates an array of 3 arrays
Another answer suggests using an associative array but it is generally not a good idea:
http://andrewdupont.net/2006/05/18/javascript-associative-arrays-considered-harmful/
If you want 'keyed' array I think you need something like
array['key'] = { comment: 'comment', youtube: 'ODD2345UI' };
Here's my test for you: http://jsfiddle.net/neuroflux/MtuLc/1/
var galleryData = [];
$("#gallery li.gallery-image-item:not(:first)").each(function() {
galleryData.push({comment: 'comment', youTube: 'ODOIUOIhd'});
});
Note that I fixed your missing bracket and changed your Array notation. I've also used jQuery just to output onto the page.

JavaScript Variable Declaration

This is a really stupid question, but I'm just drawing a blank here...
What type of variable declaration is this:
var s1 = [1,2,3,4]
Also, How can I construct a variable like this from multiple objects when the amount of those objects is unknown. This is what I came up with, which doesn't work.
var s1 = [];
for(x in data[i].uh) {
s1 += data[i].uh[x];
}
var s1 = [1,2,3,4]
is an array declaration of four integers using "Array Literal Notation"
You don't need a loop to copy the array, simply do this:
var s1 = data.slice(0);
or in your example you might want this:
var s1 = data[i].uh.slice(0);
Read more about copying arrays here: http://my.opera.com/GreyWyvern/blog/show.dml/1725165
"The slice(0) method means, return a
slice of the array from element 0 to
the end. In other words, the entire
array. Voila, a copy of the array."
That is called an Array, which can be declared with new Array() or by using the array literal [] as in your example. You can use the Array.push() method (see docs) to add a new value to it:
var s1 = [];
for(x in data[i].uh) {
s1.push(data[i].uh[x]);
}
This
var s1 = [1,2,3,4]
is an array declaration.
To add an element to an array, use the push method:
var s1 = [];
for(x in data[i].uh) {
s1.push(data[i].uh[x]);
}
s1 is an array, it's a proper Javascript object with functions.
var s1 = [];
is the recommend way to create an array. As opposed to:
var s1 = new Array();
(see: http://www.hunlock.com/blogs/Mastering_Javascript_Arrays)
To add items to an array use s1.push(item) so your code would be:
var s1 = [];
for(x in data[i].uh) {
s1.push(data[i].uh[x]);
}
As a side note, I wouldn't recommend using for-in, at least not without checking hasOwnProperty.
It's declaring a local variable with an Array with 4 members.
If you want to append to an Array, use the push() method.
That is an array. To add to arrays you would use Array.push(). For example:
var s1 = [];
s1.push(1);
s1.push(2);

Issues Stringifying a multidimensional array with json.js

I have problems with .stringify(), but I think my JavaScript array must be wrong, here's my code:
var questions = new Array();
$('#Valid').hover(function(){
for (i=0;i < $('.Questions').length;i++){
questions[i]=new Array();
questions[i]['numero']=$('.Numero:eq('+i+')').html();
questions[i]['question']=$('.ItemInput:eq('+i+')').val();
questions[i]['variable']=$('.VarName:eq('+i+')').val();
}
var stringJSON=JSON.stringify(questions)
alert (stringJSON)
})
The stringJSON var returns :
[[]]
What am I doing wrong?
Arrays have integer keys, not strings.
Use an object instead; objects in JS sort of look like associative arrays:
var questions = new Array();
$('#Valid').hover(function(){
for (var i=0;i < $('.Questions').length;i++){
questions[i]={};
questions[i]['numero']=$('.Numero:eq('+i+')').html();
questions[i]['question']=$('.ItemInput:eq('+i+')').val();
questions[i]['variable']=$('.VarName:eq('+i+')').val();
}
var stringJSON=JSON.stringify(questions);
alert(stringJSON);
});
Setting questions[i] to {} is the key.
You can shorten this syntax:
var questions = new Array();
$('#Valid').hover(function(){
for (var i=0;i < $('.Questions').length;i++){
questions[i] = {
numero: $('.Numero:eq('+i+')').html(),
question: $('.ItemInput:eq('+i+')').val(),
variable: $('.VarName:eq('+i+')').val()
};
}
var stringJSON=JSON.stringify(questions);
alert(stringJSON);
});
Fix:
Replace questions[i]=new Array(); with questions[i] = {}; (or = new Object(); if you really want this "ugly" syntax).
Explanation:
Arrays in JavaScript are like arrays in languages like C: They only support integer indexes in the interval [0, array.length).
For associative arrays, you use objects which are created using the object literal {}.
First, your "questions" variable appears to be intended as a real array. What you're putting inside the array, however, are not real arrays — they're just objects with properties.
var questions = [];
$('#Valid').hover(function(){
for (var i=0;i < $('.Questions').length;i++){
questions[i] = {
'numero': $('.Numero:eq('+i+')').html(),
'question': $('.ItemInput:eq('+i+')').val(),
'variable': $('.VarName:eq('+i+')').val()
};
}
var stringJSON=JSON.stringify(questions)
alert (stringJSON)
});
(Note that I also added a var for the "i" loop variable - important!)
Now, as to why the thing is coming up empty, well, I suspect it's because $('.Questions') is coming up empty.
Oh and also, this is something you could use the jQuery ".map()" API for:
$('#Valid').hover(function() {
questions = $('.Questions').map(function(i, q) {
return {
'numero': $('.Numero:eq('+i+')').html(),
'question': $('.ItemInput:eq('+i+')').val(),
'variable': $('.VarName:eq('+i+')').val()
};
}).get();
var stringJSON = JSON.stringify(questions);
alert(stringJSON);
});
That's a little nicer because it gets around the ugly problem of re-evaluating $('.Questions') on every iteration of the loop.

Categories

Resources