Array Says Its Length Is 0 But Console Says Otherwise - javascript

Good Afternoon,
I have encountered a problem with my code:
I have a for function adding values to an array variable but whenever I run the page it gives me an error stating that the array is empty. Here's the code adding values to the array:
if(this.Type === "Image") {
this.Frames = [];
for(var i = 0; i <= Sources.length - 1; i++) {
var Img = new Image();
Img.src = Sources[i];
this.Frames["Frame" = i] = Img;
}
} else {
this.Frames = [];
for(var i = 0; i <= Sources.length - 1; i++) {
this.Frames["Frame" + i] = Sources[i];
}
}
The code runs fine. How do I know that? Well I went on the JavaScript console and checked what value the array had. It said Frames[0], but when I collapsed it, it had Frame0, and when I collapsed that, the source it had was the correct source. So, what is going on with this? Is it a glitch or am I doing something wrong that I didn't know of before?
Thanks in advance.

That's because JavaScript only has numeric arrays. It does not have associative arrays.
When you do: this.Frames["Frame" + i] = Sources[i];, what you are doing is adding a property to the array (in JavaScript, everything is an object, and can therefore have properties). You are not actually pushing to the array.
One thing you can do is use an object instead: this.Frames = {};.
Or, you can .push() onto the array and use it as a numeric array.
this.Frames[i] = Sources[i];
// or
this.Frames.push(Sources[i]);

The .length property of JavaScript arrays only counts properties whose names are strings that look like integers (like "0", "1", etc). You can add whatever properties you want to an array instance, but only numeric properties affect the length of the array.

Related

Assign a array of indexes as an object value

I have an assignment which i need to sole but i am really stuck and can't make a progress. The assignment consist in an array of elements like this
const appleHolderLine = ['Rome', 'Ambrosia', 'Rome', 'RedDelicious', 'Akane','RedDelicious', 'SweeTango', 'RedDelicious', 'RedDelicious', 'Opal', 'Winesap', 'RedDelicious', 'Empire', 'RedDelicious', 'Liberty'];
Firstly it is needed to declare a variable lineCount which count for every element of the array and a reference to an object called appleMap.
Than the challenge consist in looping through the array and the elements of the array would be the object keys with no duplicates and the values would be an array of idexes of the specific element place of the array. To give an example how it should look like:
Example:
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
console.log (lineCount, appleMap)
Should Log:
5, {'GreenApples':[0], 'RedDelicious': [1,4], 'OrangeApples':[2], 'PurpleApples': [3]}
My progress so far
var lineCount = 0;
var appleMap = {};
for (let i = 0; i < appleHolderLine.length; i++){
lineCount++;
// if element in the array exist in the array
appleMap[appleHolderLine[i]] = [i];
}
Could you give me a hint of how to solve this, i am really stuck.
Basically you can create an empty array the first time and keep pushing like below
var lineCount = 0;
var appleMap = {};
for (let i = 0; i < appleHolderLine.length; i++){
lineCount++;
if(!appleMap[appleHolderLine[i]])
appleMap[appleHolderLine[i]] = []
appleMap[appleHolderLine[i]].push(i);
}
You could use Array.prototype.reduce which is a more advanced construct javascript provides. Please refer to answer by CodeManiac below for the same.
The above answer is to clarify the basic idea and hint on how you could think
Also, lineCount can be obtained by using appleHolderLine.length directly.
You don't need an extra variable ( Line count ) here, simply loop over the value use, use the index to access value, check if there's nothing present for that key then just initialize it with empty array, push index to the key in each iteration
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
var appleMap = {};
for (let i = 0; i < appleHolderLine.length; i++){
if(!appleMap[appleHolderLine[i]]){
appleMap[appleHolderLine[i]] = []
}
appleMap[appleHolderLine[i]].push(i);
}
console.log(appleMap)
You can simply use reduce
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
let final = appleHolderLine.reduce((op,inp,i)=>{
op[inp] = op[inp] || []
op[inp].push(i)
return op
},{})
console.log(final)
Line count is simply same as length of array, let lineCount = appleHolderLine.length
I suppose, the shortest answer is the functional one.
const appleHolderLine = ['GreenApples', 'RedDelicious','OrangeApples', 'PurpleApples', 'RedDelicious']
result = appleHolderLine.reduce((a,c,i) => { if(a[c]) a[c].push(i); else a[c]=[i]; return a; }, {})
console.log(result)
But I am not sure that you are expected to deliver a functional solution. Still, you might find it useful. The idea is that the reduce method starts with an empty object and iterates through the array. In each iteration, it checks if the current element c is already a field of the accumulator a. If so adds its index i to the specific field, if not, initializes the field with the current element as name and the index as a single-element array as value.

Dynamically created Array always filled with variables

Why is the logged Array always filled with data? Shouldnt it be an array with only one then two then three arrays in it?
var theArray=[];
function insertValues(species,quantity){
var w = window;
w[species]= [];
for(let i =0; i<quantity;i++){
w[species].push({
species:species,
randomValue:Math.random()*10
})
// console.log(theArray);
}
theArray.push(w[species]);
}
var listOfSpecies =[{animal:"Fish",amount:5},{animal:"Shark",amount:5},{animal:"Algae",amount:5}];
for(let i = 0; i<listOfSpecies.length; i++){
console.log(theArray);
insertValues(listOfSpecies[i].animal,listOfSpecies[i].amount);
}
Woah! Firstly, don't assign to window! (unexpected things will almost definitely occur).
Also, JavaScript objects (yes an array is an object, typeof [] === "object" // true) are passed by reference, not by value.
When you add to theArray, a new reference is created. When you go to log it to the console, it shows an empty array at first, but it has actually logged a reference to theArray, therefore, when you go to inspect the contents, it shows an array filled with values;
Even try the example below, the same thing occurs (albeit much simpler to follow)
var arr = [];
for (var idx = 0; idx < 3; idx++) {
console.log(arr);
arr[idx] = idx;
}
to prevent this, you would need to copy the array, like so:
var newArray = Object.assign([], theArray);
Object.assign copies the values of the array (or object), returning a new array (again, or object), but does not create a reference back to the original array or object.

Javascript / JQuery - How do I find the size of this array of objects?

I have this code to iterate through an array of objects:
for (vehicleIndex in scenes[sceneID].vehicles) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
...
}
but I need to know how to determine the number of items being iterated through so that on the final item, I can execute a particular function. How do I do this?
Example in ES5:
Object.keys( scenes[sceneID].vehicles ).forEach(function( vehicle, index, arr ) {
if( index === arr.length - 1 ) {
// do something on last entry
}
});
Even tho, "last" just means the last element which was looped over. Since there is specific order within a Javascript object (they are infact unordered). However, we could sort the object key names manually by just chaining a .sort() before the .forEach()
var arraySize = scenes[sceneID].vehicles.length;
var i;
var currentItem;
for (i = 0; i < arraySize; i++) {
currentItem = scenes[sceneID].vehicles[i];
if (i == arraySize - 1) {
// do something special
} else {
// do something not so special ;-)
}
}
scenes[sceneID].vehicles should have a length property.
for (vehicleIndex in scenes[sceneID].vehicles) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
...
}
doSomethingWithLastItem(vehicleId);
Because JS does not have block scope, by the time your loop finished vehicleId will be the last item's id.
In generic terms you can get the size of an array by accessing the .length property. You can also get the size of an object using Object.keys(obj).length.
Use this to find the length:
scenes[sceneID].vehicles.length
length is a built-in property in arrays. However, if you want to check for the last item, you have to check
scenes[sceneID].vehicles.length - 1
as arrays are zero-indexed.
Also, you should not use for...in to loop on arrays - if someone extends Array.prototype (or worse, Object.prototype), then you will not be happy. Use a normal for loop (which also allows you to use the final item easily):
var len = scenes[sceneID].vehicles.length;
for (var vehicleIndex = 0; vehicleIndex < len; vehicleIndex++) {
vehicleID = scenes[sceneID].vehicles[vehicleIndex];
//...
}
//Do something with the final item here
//Similar to this: itemFunc(vehicleID);
See this SO question for more details.

sum index in JavaScript foreach

In the following code sample i get a strange behavior
var data = ['xxx', 'yyy'];
for (var i in data)
{
var a = i;
var b = data[i];
}
The two first iterations works just fine. I get index "0" and "1" in i, but then it loops one extra time and now the i is "sum". Is this by design or what is this extra iteration used for? The result in my case is always empty and it messes up my code. Is there a way to not do his extra loop?
BR
Andreas
It looks like you (or some other code you've included) have added extra properties onto the Array prototype. What you should be doing is checking to see whether the object you're iterating over actually has that property on itself, not on its prototype:
for (i in data) {
if (data.hasOwnProperty(i)) {
a = i;
b = data[i];
}
}
That said, you should never use for .. in on arrays. Use a regular for loop.
See here for more information: http://yuiblog.com/blog/2006/09/26/for-in-intrigue/
You are looping through an Array, not through an Object. For arrays it's better to use:
for (var i=0; i<data.length; i=i+1){
/* ... */
}
In your loop every property of the Array object is taken into account. That makes the for ... in loop for array less predictable. In your case it looks like sum is a property (method) that's added to Array.prototype elsewhere in your code.
There are more ways to loop through arrays. See for example this SO-question, or this one
Just for fun, a more esoteric way to loop an array:
Array.prototype.loop = function(fn){
var t = this;
return (function loop(fn,i){
return i ? loop(fn,i-1).concat(fn(t[i-1])) : [];
}(fn,t.length));
}
//e.g.
//add 1 to every value
var a = [1,2,3,4,5].loop(function(val){return val+1;});
alert(a); //=> [2,3,4,5,6]
//show every value in console
var b = [1,2,3,4,5].loop(function(val){return console.log(val), val;});
Here's a way to safely iterate.
var data = ['xxx', 'yyy'];
for (var i = 0; i < data.length; i++)
{
var a = i;
var b = data[i];
}
What you are getting is an method coming from extending the Array object, I guess you are using some library where is something like
Array.prototype.sum = function () {...};
Perhaps setting data like this would work better: var data = {0:'xxx', 1:'yyy'};
First of all data is an object. Try to add console.log(a); and console.log(b); inside your loop and you'll see.

JavaScript Array

I usually script/program using python but have recently begun programming with JavaScript and have run into some problems while working with arrays.
In python, when I create an array and use for x in y I get this:
myarray = [5,4,3,2,1]
for x in myarray:
print x
and I get the expected output of:
5
4
3
..n
But my problem is that when using Javascript I get a different and completely unexpected (to me) result:
var world = [5,4,3,2,1]
for (var num in world) {
alert(num);
}
and I get the result:
0
1
2
..n
How can I get JavaScript to output num as the value in the array like python and why is this happening?
JavaScript and Python are different, and you do things in different ways between them.
In JavaScript, you really should (almost) always iterate over an array with a numeric index:
for (var i = 0; i < array.length; ++i)
alert(array[i]);
The "for ... in" construct in JavaScript gives you the keys of the object, not the values. It's tricky to use on an array because it operates on the array as an object, treating it no differently than any other sort of object. Thus, if the array object has additional properties — which is completely "legal" and not uncommon — your loop will pick those up in addition to the indexes of the "normal" array contents.
The variable num contains the array item's index, not the value. So you'd want:
alert(world[num])
to retrieve the value
The for var in... loop in JavaScript puts the keys in the variable instead of the actual value. So when using for var ... you should do something like this:
var world = [5, 4, 3, 2, 1];
for ( var key in world ) {
var value = world[key];
alert(key + " = " + value);
}
And note that this way of looping is best used when you're using objects instead of arrays. For arrays use the common:
for ( var i = 0, j = arr.length; i < j; i++ ) { ... }
Or if you're targeting modern browser you can use the forEach-method of arrays:
var arr = [1, 2, 3];
arr.forEach(function(num) {
alert(num);
});
The for...in loop loops over all key elements; not the values.
I would recommend you to use
for(var i=0; i<arr.length; i++){
alert(arr[i]);
}
When you use the in operator num becomes a key. So simply use this key to get a value out of the array.
var world = [5,4,3,2,1]
for (var num in world) {
alert(world[num]);
}
try this.
var world = [5,4,3,2,1]
for(var i=0;i<world.length;i++){
alert(world[i])
}
Because javascript in your case is printing the index of the element, not the value.
the result you got is just element index,if you want to get element value
your code should like this
var world = [5,4,3,2,1]
for (var num in world) {
alert(world[num]);
}
The for in iteration in JavaScript works only for the object data type. The way it works is that it lets you iterate over the attributes of an object. arrays are objects in JavaScript, but the for in only works on its attributes, not the array values.
For example you might define an array as such:
var arr = [1,2,3];
And you can assign attributes to this array, because it's actually an object:
arr.foo = "bar";
arr["1"] = 2;
Now when you use the for in iteration method you will be able to iterate over the attributes we just assigned above;
for(var i in arr) console.log(i);
To iterate over the actual array values you need to use the for(var i=0; i<arr.length; i++) construct.
Hope this helps.
In javascript it's advised to loop Arrays different from looping Objects. You are using an object loop, which may return unexpected result (for instance if the Array.prototype was extended with custom methods you would iterate those too, and it does't guarantee the order of the array is preserved). There are many ways to loop through an array, using it's index:
// regular
var arr = [1,2,3,4,5]
,i
;
for (i=0;i<arr.length;i++) {
console.log(arr[i]);
}
// using while
var arr = [1,2,3,4,5]
,i = 0
;
while ((i = i + 1)<arr.length) {
console.log(arr[i]);
}
// using while reversed
var arr = [1,2,3,4,5]
,i = arr.length
;
while ((i = i - 1) > -1) {
console.log(arr[i]);
}
Note: Why not use i++ or i--? To avoid confusion, index out of range-errors and to satisfy JSLint

Categories