If i declare this
var data = [];
data [300] = 1;
data [600] = 1;
data [783] = 1;
I have an array of length 784 but with only 3 defined items within it.
Since splice(300,1) would delete the item and the index but would also shift every consecutive position, how can i delete the object in the index 300 from the array without altering the order of the array so when i use
for(var x in data)
it can correctly iterate only 2 times, on the indexes 600 and 783?
i tried using data[300] = undefined but the index 300 was still iterated over.
You could use delete:
delete data[300];
This sets the value of the index to be undefined, but doesn't modify the element index itself.
See more about the delete operator here.
dsg's answer will certainly work if you're going to use an array. But, if your data is going to be as sparse as it is, I wonder if a plain Javascript object might be a better choice for such sparse data where you never want the index/key to change. Arrays are optimized for consecutive sequences of data starting with an index of 0 and for iterating over a sequence of values. And, they keep track of a .length property of the highest index used minus one.
But, since you aren't really doing any of that and given the way you are storing data, you aren't able to use any of the useful features of an array. So, you could do this instead with a plain Javascript object:
var data = {};
data [300] = 1;
data [600] = 1;
data [783] = 1;
delete data[300];
This would create an object with three properties and then would delete one of those properties.
You can then iterate over the properties on an object like this:
for (var prop in data) {
console.log(data[prop]);
}
A couple things to remember: 1) The property names are always strings so your numbers would show us as "600" in the prop variable in the above iteration. 2) Iterating with the for/in technique does not guarantee any order of the properties iterated. They could come in any order since properties on an object have no innate order.
You can delete that element from the array:
delete data[300];
The full example:
var data = [];
data [300] = 1;
data [600] = 1;
data [783] = 1;
delete data[300];
var result = "";
for (var x in data) {
result += "<div>" + x + "</div>";
}
document.getElementById("output").innerHTML = result;
<div id="output" />
Related
I'm given the task to deduce and explain the lines of codes of a counter program. Below are the codes to the program which is working perfectly. I have included my explanations as comments in the code but it seems my explanation for the last 4 lines of codes (starting from ... "if(counter[index][entry] === undefined){...}") doesn't really explain it.
Can anyone please read the codes and give me a better explanation to them especially why we equate "counter[index][entry] = 1".
<script>
//an array containing a list of objects with sub arrays that has to be
//counted "separately"
var arr = [
{"gateways":["ccu1"],"manufacturer":["homematic"],"ir":["ir_no"],"ip":
["ip_cam","ip_other"]},
{"gateways":["v3"],"manufacturer":["homematic"],"ir":["ir_no"],"ip":
["ip_cam"]},
{"gateways":["v2","v3","v4","ccu2"],"manufacturer":
["homematic","intertechno"],"ir":["ir_yes"],"ip":
["ip_cam","ip_other"]},
{"gateways":["v2","ccu1","ccu2"],"manufacturer":["homematic"],"ir":
["ir_yes"],"ip":["ip_cam","ip_other"]},
{"gateways":["gw_none"],"manufacturer":["homematic"],"ir":
["ir_no"],"ip":["ip_cam"]},
{"gateways":["v3","ccu2"],"manufacturer":
["homematic","fs20","intertechno","elro","Eltako Enocean"],"ir":
["ir_yes"],"ip":["ip_cam","ip_other"]},
{"gateways":["v3","v4"],"manufacturer":["homematic"],"ir":
["ir_no"],"ip":["ip_other"]},
{"gateways":["v3","v4"],"manufacturer":["homematic"],"ir":
["ir_no"],"ip":["ip_other"]},
{"gateways":["v2"],"manufacturer":["intertechno"],"ir":["ir_yes"],"ip":
["ip_other"]},
{"gateways":["v4"],"manufacturer":["homematic","intertechno"],"ir":
["ir_yes"],"ip":["ip_cam","ip_other"]}
];
//console.log(arr.length);
//first we create an empty array "counter" to contain the separately
//counted objects
var counter = [];
//we then use "for loop" to loop through the "arr" array to access the
//first index
for(var i=0; i<arr.length; i++) {
//console.log(arr[i]);
// we create a variable "obj" to store the first index object of
//the "arr" array and because it is a loop,
//it will loop till the last object
var obj = arr[i];
//so if we console log "obj", it will display the entire indexes in
//the "arr" array including keys
//console.log(obj);
//we then use "for in" loop to access all the keys in the variable
// "obj" because we wanna count the number
//of all respective sub arrays
for(var index in obj) {
//so if we console log "index", it will display the entire keys in
// the "obj" variable; ie:
//in every object, it will run 4X to access all the keys
//console.log(index);
//in the next two lines of codes, we have to check if the keys in
// our counter array already exist because
//this is where we gonna put or store our counted respective sub
//arrays. if it doesn't exit, we create it.
if(counter[index] === undefined) {
counter[index] = [];
}
//so if we console log "counter[index]", it will show empty
//arrays which is gonna contain the respective key counts
//console.log(counter[index]);
//next we save the respective arrays to be counted without the
// keys in a variable "arr2".
var arr2 = obj[index];
//console.log(arr2);
//now we wanna loop through the "arr2" array because it
//contains the entries (in arrays) we wanna count
///starting from the first index to the last
for(var j = 0; j < arr2.length; j++) {
//we then store the single entries in a variable called "entry"
//(not with keys or in an array)
var entry = arr2[j];
//console.log(entry);
//in the next two lines of codes, we have to check if the keys
//in our counter array exist because this is where
//we would count "entry"
if(counter[index][entry] === undefined) {
counter[index][entry] = 1;
//console.log(counter[index][entry]);
} else {
counter[index][entry]++;
}
}
}
}
console.log(counter);
</script>
If counter[index][entry] is undefined, it means that we haven't began counting it yet. So we need to start counting it. So we count once, which sets the counter to 1.
If counter[index][entry] does exist (the else clause), it means that there's already a number in counter[index][entry] (because that's what we initialize it to if it doesn't), so just increment the number by one.
Another, perhaps clearer way of writing this would be:
if (counter[index][entry] === undefined) {
counter[index][entry] = 0; // If it doesn't exist, initialize counter to 0.
}
counter[index][entry]++; // Here the counter is a number for sure, increment once.
Basically it's trying to count how many each specific property exists. Eg, how many occurences of gateway v2, how many times ip_other exists etc.
The part with 'if(counter[index] === undefined)' is weird. Counter is an array. And index is the key from an object (namely gateway, manufacturer, ip and ir) So basically it's trying to set keys on an array. Although this is valid javascript, counter should be an object instead of an array to be 'more logical'. Hence the code looks a bit confusing.
Anyways, the rest works like madara posted.
I am working on an exercise where I prompt the user for a list of names, store the list of names in an array, sort the array in ascending order, and print the list of names (one per line). When I do so, I see a numeric value displayed instead of one name per line. Why is this happening?
var namesArray = [];
do {
var names = prompt("Enter a name: ");
namesArray.push(names);
} while (names != "")
namesArray.sort();
for (var name in namesArray) {
document.write(name);
}
When you use this construct:
for (var name in namesArray) {
the value of name will be the index in the array (the property name). If you want the actual value in the array, you have to use that property name/index to get the value:
document.write(namesArray[name]);
Of course, you really should not iterate arrays that way in the first place because that iterates all the enumerable properties of the array object (potentially including non array elements) as you can see in this example. Instead, you should use a traditional for loop as in this code example that follows:
var namesArray = [];
do {
var names = prompt("Enter a name: ");
namesArray.push(names);
} while (names != "")
namesArray.sort();
for (var i = 0; i < namesArray.length; i++) {
document.write(namesArray[i]);
}
Other options for iterating the array:
namesArray.forEach(function(value) {
document.write(value)
});
Or, in ES6, you can use the for/of syntax which does actually work how you were trying to use for/in:
for (let value of namesArray) {
document.write(value);
}
You also may want to understand that using document.write() after the document has already been parsed and loaded will cause the browser to clear the current document and start a new one. I don't know the larger context this code fits in, but that could cause you problems.
First, in a for..in loop, here name represents the keys and not the values in your array (you should use namesArray[name])
Also there is another important thing to note. An array is not recommended to be looped through using for..in and if so, you should do it like this:
for (var key in array) {
if (array.hasOwnProperty(key)) {
// then do stuff with array[key]
}
}
The usual preferred ways to loop through an array are the following:
A plain for loop
for (var i = 0, l = array.length; i < l; i++) {
// array[i]
}
Or a higher order function with Array.prototype.forEach (IE9+ if you need compat with IE)
array.forEach(function (item) {
// do something with the item
});
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.
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.
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.