Filling multidimensionnal array in JavaScript - javascript

I've a little problem in JavaScript.
I need to get an array width date as keys and events as values.
In PHP I would do something like this :
$var = new array();
Loop
$var[$date][] = $event;
End loop
Do you know what I mean ?
Thanks,
Regards

In javascript, you can create a data structure like that this way:
var events = {
'2009-09-09': [],
'2010-10-10': [],
'2011-11-11': []
};
The events = { ... } is an object literal in javascript. Objects in javscript act very much like hashes with properties as keys, so this is essentially going to act as a hash keyed on dates. Each date is initialized with an empty array.
And you can fill it up with events like this
events[date].push(event);
If you don't know the dates ahead of time, you can dynamically fill the hash. So, you'd start with just an empty hash:
var events = {};
Then you'd check for the date key every time you go to add an event, like this:
if (!(date in events)) events[date] = [];
events[date].push(event);
The date in events checks to see if the key exists, and the ! negates it. So if the date key does not exist, it initializes the date key with an empty array. Then it pushes the event for that date as normal.

In Javascript key-value mappings are handled by Objects. An empty object is just {}. You can do this sort of thing like (note that var is a reserved word in Javascript so I can't copy your example exactly):
var variable = {};
var date_list = [1,2,3];
var event_list = [4,5,6];
for (i in date_list){
var key = date_list[i];
var value = event_list[i];
variable[key] = value;
}
// variable now contains: {1:4, 2:5, 3:6}
console.log(variable[1]);
// prints 4
EDIT: That's the basic syntax. If you want to have an array for each key, just do something like that but with arrays instead of numbers in event_list. For example:
my_dates = {'2011': [1,2,3], '2010': [6,7,8]}

To add an element to a list you can use the push javascript method of array objects...
events_by_date = {};
...
for (var i=0; i<events.length; i++) {
if (!events_by_date[events[i].date]) {
// This is the first event on this date
// so create the list
events_by_date[events[i].date] = [];
}
// Add the event to the list of events in that date
events_by_date[events[i].date].push(events[i]);
}

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 :)

Creating many random arrays for use as elements in another array

Consider:
var main = []
Now I want to generate many (289 to be exact) Arrays to be elements in the main one. Each of these arrays will have be like:
var subobject = {x:"A", y:"B", terrain:"C", note:"D"}
Generating the values are no problem, and I can easily put those values in a already defined subobject = {} and push(), but I can't figure out how to iterate a script each time which creates a new object and then push() into var main.
The naming of the subobject is unimportant, I'm looking for solution inwhich I can pull specific information such as:
main[0].x // get x value of the subarray in 0 location in main
main[5].note// get note value of the subarray in 5 location in main
(would it make a difference if every array had the same name? since I would never access subobject directly (after being pushed into main), but through main[X].YYY or would it have to be via main[X].subarray[Y] ?)
for (var i = 0; i < 289; i++) {
main.push({x: getRandomX(), y: getRandomY(), terrain: getTerrain(), note: ""});
}
as long as you create new objects {} before you push them to the array it is ok.
it doesn't matter if you assign the new object to the same variable (ie subobject)
you access them later like this:
main[0].x // get the value of x of the first element
[x:"A", y:"B", terrain:"C", note:"D"] isn't valid javascript, I think you want an object here:
{x:"A", y:"B", terrain:"C", note:"D"}
And to push each generated value, you can use a for loop
for (var i = 0; i < 9; i++) {
//do something, for example, generate a value
}
Arrays are only numerically indexed.
If you want named keys you have to use objects.
Here's the wrong way to do it.
var main = [],
subobject = {x:"A", y:"B", terrain:"C", note:"D"};
for(var i=0; i<289; i++){
subobject["x"] = Math.random();
subobject["terrain"] = Math.random();
//continue adding values using keys
main.push(subobject);
}
The thing is if you just use the same object your going to access that object every time you iterate it, and you'll replace it's value.
So you should do it like this.
var main = [],
subobject = {};
for(var i=0; i<289; i++){
subobject = {};//new object to make for uniquness
subobject["x"] = Math.random();
subobject["terrain"] = Math.random();
//continue adding values using keys
main.push(subobject);
}
You access members like this.
main[0].x;//value of x at index 0
//next index
main[1].terrain;//value of terrain at index 1
Collisions will only happen if you set the same index twice.
main[2].x = "value";
main[2].x = "replace value by accident";
Unless you want to change the value for some reason.
A different index will always give you a different object if you set a different one each time.

Can't reference array by index

I have an array defined as:
var subjectCache = [];
I then have some code to build it up, which is working ok.
However, if I try to reference the array by an index, e.g.:
var x = subjectCache[0];
or
var x = subjectCache[1];
I get undefined.
Also subjectCache.length is always 0 (zero).
if I try to reference it by its key, e.g.:
var x = subjectCache['12345'];
it works.
Is this normal? Shouldn't I be able to reference it by its index whatever?
I'm using Internet Explorer, if it makes a difference (and it probably does :( )
[Edit]
this is the code I'm using to build the array, although I really don't think it is to blame.
It's a callback from a webservice call. This is working fine and the array is being populated.
var subjectCache = [];
var subjectCacheCount = 0;
function refreshSubjectsCallback(data) {
// update subjects
// loop through retrieved subjects and add to cache
for( i=0; i < data.length; i++ )
{
var subject = data[i];
var subjectid = subject.SubjectId;
subjectCache[subjectid] = subject;
subjectCacheCount += 1;
}
}
[/Edit]
You're probably assigning keys manually instead of using subjectCache.push() to add new elements to the array:
var array = [];
array['foo'] = 'bar';
console.log(array.length); // 0
The length attribute isn't going to reflect those changes the way you'd expect:
> var a = [];
undefined
> a[100] = 2; // The previous `100` entries evaluate to `undefined`
2
> a.length;
101
Instead, use an object:
var object = {};
object['foo'] = 'bar';
for (var key in object) {
var value = object[key];
console.log(value);
}
From your symptoms, it sounds like you are trying to treat the array as an associative array.
In Javascript, arrays work like this:
var a = [];
a[1] = 10;
alert(a.length);
Objects work like this:
var o = {};
o.myProp = true;
o["myOtherProp"] = false;
Arrays only work with numeric keys not strings. Strings assign properties to the object, and aren't counted as part of length nor it's numeric indices.
When building the array, make sure you are assigning to a numeric position within the array.
No, it will not work, because you haven't created arrays but objects.
you will have to access it by its key.
var x = subjectCache['12345'];
If this works and subjectCache.length doesn't, I think you are making an object not an array. You are confused.
Somewhere along the road you lost the array, and the variable subjectCache points to a different kind of object.
If it was an array, it can't have the length zero and contain an item that is reachable using subjectCache['12345']. When you access an item in an array it doesn't make any difference if you use a numeric index or a string representing a number.

Getting Length of Object in Javascript / jQuery

I am trying to set up an array in jQuery and I then need to do a for loop on it. But it seems that I cant use an associative array for some reason?
var items = new Array();
items['foo'] = 123456;
items['bar'] = 789012;
items['baz'] = 345678;
items['bat'] = 901234;
alert(items.length);
This is just a test, but it return 0?
You can't make associative array in JavaScript like what you want, instead you can use Object.
For example:
var items = {
foo : 123456,
bar : 789012,
baz : 345678,
bat : 901234
}
And to calculate the length you can do:
var getObjectSize = function(obj) {
var len = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) len++;
}
return len;
};
Use: getObjectSize(items); // output: 4
For more see here.
Another one is:
Object.keys(items).length;
But not supported by all browsers.
var items = new Array();
items['foo'] = 123456;
The problem lies in the very first line. You believe that you are adding an item to the array at the index foo, but you are actually adding a property to the items variable with a key foo and value 123456. If you were to type items.foo it would give you back your 123456.
The problem with this approach is that adding a property to an array does not magically increase it's length.
If you want to have non-numeric indexes, you need to use an object instead of an array:
var items = {
foo: 123456,
bar: 789012,
baz: 345678,
bat: 901234
};
Another approach might be to set up two different arrays, which you construct in parallel:
var items = [], items2 = [];
items.push('foo');
items2.push(123456);
// etc.
alert(items2.length);​
The efficiency of this approach depends on how you'll use it. If you're only going to loop through the list of items and do something to each of them, this approach may be more efficient. But if you need to use it like an associative array (items['foo']), then you're better off building an object.
The .length property returns the highest numerical index of the array. Thus, in your case, there is no numerical index and it returns 0. Try
items[98] = "something";
items.length will be 98..! Use the .length property with caution, and if you also want to count the non-numerical indici, loop over the Object (an Array is also an Object) and count its ownProperties.

Categories

Resources