Dynamically created Array always filled with variables - javascript

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.

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.

Copying array onto the "this" variable (creating an Array-like object)

Is there a better way to copy an array onto the this variable
function obj(arr) {
for (var i=0, l=arr.length; i<l; ++i) {
this[i] = arr[i];
}
this.length = arr.length;
}
var o = new obj([1,2,3,4]);
console.log(o[0]); // Outputs 1
Is there any other way to do it, instead of iterating over the whole arr ?
You can use Array#push this way:
function obj(arr) {
Array.prototype.push.apply(this, arr);
}
This will treat this like an array, adding all the elements from arr and setting length correctly. See also Function#apply.
But of course there is still an internal loop. You cannot copy / move a collection values to another collection without iterating over it (unless, I guess, the collections use structural sharing)
You could do it like this:
function obj() {
return this;
}
var o = obj.apply([1,2,3,4]);
console.log(o[0]); // Outputs 1

Array Says Its Length Is 0 But Console Says Otherwise

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.

Sort a three dimensional array in Javascript

Consider this Array
var LIST =[];
LIST['C']=[];
LIST['B']=[];
LIST['C']['cc']=[];
LIST['B']['bb']=[];
LIST['C']['cc'].push('cc0');
LIST['C']['cc'].push('cc1');
LIST['C']['cc'].push('cc2');
LIST['B']['bb'].push('bb0');
LIST['B']['bb'].push('bb1');
LIST['B']['bb'].push('bb2');
I can loop through this array like
for(var i in LIST){
console.log(i)//C,B
var level1=LIST[i];
for(var j in level1){
console.log(j)//cc,bb
// etc...
}
}
Fine.. I have few basic questions.
1.How to sort the array in each level?
One level can be sort by .sort(fn) method . How can i pass to inner levels?
2.Why the indexOf method does not works to find the elements in first two levels?
If it's because of the a non string parameter .. how can i search an array items in array if the item is not string?
3.How for(var i in LIST) works ?
I just need a basic understanding of indexing and looping through array ..
Thanks ..
LIST is NOT a three dimensional array in Javascript, it is just an array.
//declare an array which names LIST.
var LIST = [];
//set a property named 'C' of the LIST to be an array.
LIST['C']=[];
//set a property named 'B' of the LIST to be an array.
LIST['B']=[];
//set a property named 'cc' of the 'LIST.C'(which is an array object)
LIST['C']['cc']=[];
//set a property named 'bb' of the 'LIST.B'(which is an array object)
LIST['B']['bb']=[];
The fact is you only need to let the last level to be an array, see my example code below.
function iterateOrderd(obj) {
if (obj instanceof Array) {
obj.sort();
for (var j = 0, l=obj.length; j < l; j++) {
console.log(obj[j]);
}
} else {
var sortable = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
sortable.push(i);
}
}
sortable.sort();
for (var j = 0, l=sortable.length; j < l; j++) {
console.log(sortable[j]);
iterateOrderd(obj[sortable[j]]);
}
}
}
var LIST = {};
LIST['C'] = {};
LIST['B'] = {};
LIST['C']['cc']=[];
LIST['B']['bb']=[];
LIST['C']['cc'].push('cc0');
LIST['C']['cc'].push('cc1');
LIST['C']['cc'].push('cc2');
LIST['B']['bb'].push('bb0');
LIST['B']['bb'].push('bb1');
LIST['B']['bb'].push('bb2');
iterateOrderd(LIST);
You need to know that Array inherits from Object.
In JavaScript, any Object instance is an associative array(!), so acts like an Array in PHP. For example:
var o = {}; // or new Object();
o['foo'] = 'bar';
o[0] = 'baz';
for (i in o) { console.log(i, o[i]); }
Sorting an Object does not make much sense. indexOf would kinda work in theory, but is not implemented.
Arrays are ordered lists. Array instances have push(), length, indexOf(), sort() etc., but those only work for numerical indexes. But again, Array inherits from Object, so any array can also contain non-numerical index entries:
var a = []; // or new Array();
a[0] = 'foo'; // a.length is now 1
a.push('baz'); // a[1] === 'baz'
a.qux = 1; // will not affect a.length
a.sort(); // will not affect a.qux
for (i in a) { console.log(i, a[i]); }
I recommend playing around with arrays and objects, and you'll soon get the point.
What is your sorting criteria ? I mean how will you say array firstArray comes before secondArray?
regarding the for (counter in myArray), counter will take values of an array element in every iteration.
for (counter in [0,1,5]), counter will have values 0, 1 and 5 in the 3 iterations.
In your case, i will have values LIST['B'] and LIST['C'] in the two iterations and j will have values LIST['B']['bb'], LIST['B']['cc'], LIST['C']['bb'] and LIST['C']['cc'].
Both i and j will be arrays.

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.

Categories