Javascript 2D array generation, "strange" behavior - javascript

So basically I asked a similar question on the same topic earlier, and although I understand how and why the solutions in the answers work(which I appreciate), I cant wrap my head around as to the reason why my code doesn't work. So, the program is intended to generate a 2 dimensional array, which should replicate a multiplication table. However, the rows' values are repeated, instead of being appropriately different.
So basically, it produces
[ [3, 6, 9],
[3, 6, 9],
[3, 6, 9] ] instead of the intended [ [1, 2, 3],
[2, 4, 6],
[3, 6, 9] ]. What apparently happens is that, after the array "rows" (which correspond to arr2, assigned by the outerloop) are assigned, in the next repeat of the loop, not only the current element arr[j] is affected, but the preceeding elements too are changed/updated following the updated(changed) value of arr2, even though not (explicitly?) addressed and reassigned.
The alert statements demonstrate this, where same index elements have different values in different loops, even though they should be assigned once and not therefore changed after being assigned(at least to my knowledge, as they are assigned/indexed only once by the for loop). So why does this behavior happen in this case?
Code below:
<script>
var arr = [];
var arr2 =[];
for (var j=0; j < 3; j++){
for (var k=0; k<3; k++){
arr2[k] = (k+1)*(j+1);
}
arr[j]=arr2;
alert("arr[" + j + "]= " + arr[j]);
alert("arr[" + (j-1) + "]= " + arr[j-1]);
}
alert("Finally: " + arr);
</script>

You have declared arr2 outside of your for loops with this line:
var arr2 = [];
That means every time you run this code:
for (var k = 0; k < 3; k++) {
arr2[k] = (k + 1) * (j + 1);
}
...you are just replacing the values in the same instance of arr2.
This line:
arr[j] = arr2;
...is storing a reference to that one instance of arr2, not a copy of it. So every time you change arr2, every reference to it in arr changes as well.

Try the following:
var arr = [], // the array to hold the answer
arr2, // another variable for inner array, note reset in loop below
j, // declaring this outside of loop for better style
k;
for (j=0; j < 3; j++){
arr2 = []; // clear inner array each time
for (k=0; k < 3; k++){
arr2[k] = (j + 1) * (k + 1); // build inner array
}
arr[j] = arr2; // add the inner array after building it.
}
console.log(JSON.stringify(arr)); // because console.log lets us see more detail than alert.
alert("Finally: " + arr);

Related

javascript unshift pop in a loop

I'm studying JS and I have this exercise that is asking to reverse an array in place (without the use of a second array) and without the use of 'reverse'. Although I already have the solution to the exercise I don't understand why my solution does not work, here it is:
function reverseArrayInPlace (arr){
const k = arr[0];
while (arr[arr.length-1] !== k){
arr.unshift(arr.pop());
}
return arr;
}
console.log(reverseArrayInPlace(arr1));
You take the end of the array and put it at the first position:
[1, 2, 3]
[3, 1, 2]
[2, 3, 1]
[1, 2, 3]
as you can see that actually doesnt reverse anything.
It will not work if your array contains duplicates of the first element.
As you are taking the first element as key, whenever any duplicate element becomes the last element, your loop exits.
Try this, just check if the two elements being selected is equal or not, if equal do not swap else swap. Iterate till the pointer k is <= the pointer j.
function reverseArrayInPlace (arr){
let first = 0;
let last = arr.length - 1;
let k = first, j = last;
while(k <= j){
if(arr[k] !== arr[j]){
let temp = arr[k];
arr[k] = arr[j];
arr[j] = temp;
}
k++;
j--;
}
return arr;
}
arr1 = [1, 2, 3, 4];
console.log(reverseArrayInPlace(arr1));
arr1 = [1, 2, 3];
console.log(reverseArrayInPlace(arr1));
This method will solve the problem without pop or unshift. Try this.
function reverseArray(array) {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
let oldArray = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = oldArray;
}
return array;
}
console.log(reverseArray([1,2,3]));

adding elements to the same array being iterated in js

I have a JavaScript array of length 3
arr = [1, 3, 8];
Is there a way to add elements to arr while I am iterating over it? I want to insert two values 10 and 20 into the existing arr. Can I do it like this? The newly added elements, 10 and 20, must also be looped over in the same for in loop.
for(var i in arr) {
if( i == 0 ) {
arr[length + 0] = 10;
arr[length + 1] = 20;
}
}
Or, what is the correct way to add elements to an array while iterating and making sure that the newly added elements will also be looped over?
You could use a for statement and check the length while iterating the array.
With for ... in statement, iteration of new elements is not granted.
Properties added to the object over which iteration is occurring may either be visited or omitted from iteration. In general it is best not to add, modify or remove properties from the object during iteration, other than the property currently being visited.
var array = [1, 3, 8],
i;
for (i = 0; i < array.length; i++) {
console.log(array[i]);
if (i === 0) {
array.push(10, 20);
}
}
You really shouldn't ever need to do this, there's probably a better method. But, if you absolutely have to, use a while loop instead:
var arr = [1, 2, 3];
var i = 0;
while (i < arr.length) {
if( i == 0 ) {
arr.push(10, 20);
}
console.log(arr[i]); // 1, 2, 3, 10, 20
i++;
}

Understanding nested for loops in javascript

I'm learning JavaScript at the moment on freecodecamp and they have an example for nested for loops in one of their excercises:
var arr = [[1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[i][j]);
}
}
With console.log = 1 2 3 4 5 6 undefined.
I understand for loops more or less, and I understand that [i] and [j] are used to access the array (I think?). I just don't understand why at the end it just prints out those numbers? I found this question asked a few years back but it just explains how to write them, not how they work:
For loop in multidimensional javascript array
I broke it down into:
var arr = [ [1,2], [3,4], [5,6]];for (var i=0; i < arr.length; i++) {
console.log(arr[i]);}
Which prints out
[ 1, 2 ]
[ 3, 4 ]
[ 5, 6 ]
undefined
and
var arr = [ [1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[i]); }}
which prints out:
[ 1, 2 ]
[ 1, 2 ]
[ 3, 4 ]
[ 3, 4 ]
[ 5, 6 ]
[ 5, 6 ]
undefined
and
var arr = [ [1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[j]); }}
which prints out
[ 1, 2 ]
[ 3, 4 ]
[ 1, 2 ]
[ 3, 4 ]
[ 1, 2 ]
[ 3, 4 ]
undefined
I understand the first two arr[i]. The loop iterates through the array and prints out the individual elements (in this case an array) and in the second one I guess it just does it twice because there are two loops. What I don't understand is:
why the last array in arr[j] is not printed out (where did the
[5, 6] go?)
why arr[i][j] suddenly eliminates the arrays and just
prints out the numbers
where the 'undefined' comes from
Could anyone help me out with this and explain the steps the code takes before printing it out in the console? I would really like to understand it but don't even know how to search for this question the right way.
var arr = [[1,2], [3,4], [5,6]];
This is an array of arrays. It is a little bit easier to read like this:
var arr = [
[1,2],
[3,4],
[5,6]
];
That makes it a little bit easier to see that you have an array of 3 arrays. The outer 'for' will loop through each of 1st level arrays. So the very first outer for loop when i=0 you are going to grab the first inner array [1,2]:
for (var i=0; i < arr.length; i++) {
//First time through i=0 so arr[i]=[1,2];
}
In the inner loop you are going to loop through each of the 3 inner arrays one at a time.
for (var j=0; j < arr[i].length; j++) {
//Handle inner array.
}
This argument grabs the length of the inner array:
arr[i].length
So on your first time through the outer loop i=0 and arr[i] is going to equal [1,2] because you are grabbing the 0th element. Remember, arrays elements are always counted starting at 0, not 1.
Finally you are printing out the results with:
console.log(arr[i][j]);
The first time through you can break it down a little. i=0 and j=0. arr[0][0] which translates as grab the first element from the outer array and then the first element from the first inner array. In this case it is '1':
[
[1,2], <-- 0
[3,4], <-- 1
[5,6] <-- 2
];
The code will loop through the first first set [1,2], then the second [3,4], and so on.
The double for loop you have above works like so:
var arr = [[1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
// i = 0, then we loop below:
for (var j=0; j < arr[i].length; j++) {
//here we loop through the array which is in the main array
//in the first case, i = 0, j = 1, then we loop again, i = 0, j = 1
console.log(arr[i][j]);
//after we finish the stuff in the 'j' loop we go back to the 'i' loop
//and here i = 1, then we go down again, i, remains at 1, and j = 0, then j = 1
//....rinse and repeat,
}
}
In plain english:
We grab the first element in the main array, which is an array itself,
we loop through that, and log at each index, this is terminated by our length condition in the second loop. We then move to to the next index of the main array, which is an array itself.... and so on, until we reach the end of the main array
To access and index in the main array, we need to use array[i] - that index holds an array - so to go INTO that array, we need to use array[i][j]
Hope that makes sense!
Despite some caveats of using for-in loops on arrays, they can imo sometimes help to clear the mess in nested loops a bit:
var arr = [[1,2], [3,4],[5,6]];
for (i in arr){
for (j in arr[i]){
console.log(arr[i][j]);
}
}
Also code visualization can clarify execution!
I know this is an old question... But because this is a popular post from ye olde google search, I feel it's helpful to add a way to visualize what's going on in nested for-loops.
As a JS teacher, I've found this method super helpful for visually-oriented people and those w/ dyslexia and related things).
// Original: https://repl.it/#justsml/nested-loop-visualizations
var nums = [[1,2,3], [4,5,6], [7,8,9]];
console.log('Example w/ Numbers:\n');
console.log('The array data: ', JSON.stringify(nums));
for (var i=0; i < nums.length; i++) {
// Main/"top" array - accessing via "arr[i]"
for (var j=0; j < nums[i].length; j++) {
// here we loop through the "child" arrays
let helpfulLabel = `nums[${i}][${j}]`
let value = nums[i][j]
console.log(helpfulLabel, 'Value=' + value);
}
}
console.log('\nExample w/ String Data:\n');
var letters = [['a', 'b', 'c'], ['d', 'e', 'f'], ['x', 'y', 'z']];
console.log('The array data: ', JSON.stringify(letters));
for (var i=0; i < letters.length; i++) {
for (var j=0; j < letters[i].length; j++) {
let helpfulLabel = `letters[${i}][${j}]`
let value = letters[i][j]
console.log(helpfulLabel, 'Value=' + value);
}
}
Preview of Results
function multiplyAll(arr) {
var product = 1;
// Only change code below this line
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
product *= arr[i][j];
console.log(product)
}
}
// Only change code above this line
return product;
}
// Modify values below to test your code
multiplyAll([[1], [2], [3]])
//multiplyAll([[1, 2], [3, 4], [5, 6, 7]]);
//multiplyAll([[5, 1], [0.2, 4, 0.5], [3, 9]])
why the last array in arr[j] is not printed out (where did the [5,
6] go?)
You may notice that if you print out j as console.log(j), it will
print 6 times as 0, 1, 0, 1, 0, 1. And what you're trying to print
is arr[j] which [5, 6] will not be displayed because its on
arr[2]
why arr[i][j] suddenly eliminates the arrays and just prints out the numbers
As you state there, arr is an array of 3 arrays. arr[i] represents
3 arrays either of [1, 2], [3, 4] or [5, 6]. And the j in
arr[i][j] represents the index of those 3 arrays. This is called
Multidimensional Array. arr[i][j] does not eliminate the array, but It selects the value in the index of j inside arr[i].
where the 'undefined' comes from
It's just chrome thingy when you use console.log. Chrome returns
undefined whenever you try to do that. Try to do it on firefox and you
will see it no longer.
function multiply(arr) {
var product = 1;
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
product *= arr[i][j];
}
}
return product;
}

How javascript(ECMAScript) assignment operator works

When I initialize an array, I found a weird situation.
JS code:
var arr = [1, 2, 3, 4, 5];
for(var i=0, arr2=[]; i < 5; arr2[i] = arr[i++])
console.log(arr2, i);
Output:
[] 0
[1] 1
[1, 2] 2
[1, 2, 3] 3
[1, 2, 3, 4] 4
arr2 initializes to [1, 2, 3, 4, 5] this is what i want
Look at this piece of code :
for(var i=0, arr2=[]; i < 5; arr2[i++] = arr[i])
console.log(arr2, i);
This code initializes arr2 to [2, 3, 4, 5, undefined]
i thought ++ operator operates before next line and both code will be same.
But, it operates differently. Why does this happen?
add explanation
I thought both for loop operates like this
var i = 0;
var arr2 = [];
check i < 5
console.log(arr2, i);
arr2[i] = arr[i];
i = i + 1;
check i < 5
....skip
is this thought wrong?
what is differance between
'arr2[i] = arr[i++];' and
'arr2[i++] = arr[i];'
Edit: removed code snippet because the question code is now fixed
Now, the issue at hand for your question is not the prefix or postfix notation, but the fact that the expression of the for loop (specifically the
arr2[i] = arr[i++] part) will be executed AFTER the loop cycle is completed. This is why your arr2 array is empty in the first iteration, the indexes are all fine but the assignment has just not happened yet.
The complete for syntax as decribed per Mozilla Developer Network is
for ([initialization]; [condition]; [final-expression])
statement
with the note for [final-expression]:
An expression to be evaluated at the end of each loop iteration. This occurs before the next evaluation of condition. Generally used to update or increment the counter variable.
To expand on your edited question regarding postfix position difference:
i++ will increment i after its next usage. So, assuming a starting value of i=3 means
arr[i] = arr2[i++] --> arr[3] = arr2[3]
and after that is done i is incremented to 4.
In the other way around i is incremented after determining the arr index, so it already has the incremented value when accessing arr2:
arr[i++] = arr2[i] --> arr[3] = arr2[4]
If your intent is to copy arr to arr2, there is no need to iterate over each element. Use slice instead:
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.slice();

Array conversion from string to int crashes the browser

I am trying to convert an array of strings to an array of integers in javascript. I saw the following solution in a coupple of threads here and in a couple of other sources so I fuigure it must be correct, however when I get to the conversion the browser crashes. I have tried with Chromium and Firefox.
Here is the source code, I am interested in what is causing this and what can be fixed:
var str = "1,2,3,3,4,5,6";
var arr1 = str.split(",");
console.log(arr1);
for(var k=0; k<=arr1.length; k++) { arr1[k] = +arr1[k]; }
In addition to the given answer, you may want to use this oneliner to create the array:
var arr1 = '1,2,3,4,5,6,7'.split(',').map(function(a){return +a;});
MDN page for Array.map
The problem is in this expression
k<=arr1.length
When k is 6, k++ increments k and it becomes 7. And then k <= arr1.length is true because arr1.length is 7. The next statement is
arr1[k] = +arr1[k];
which creates a new element in the array at index 7. So the array keeps on growing infinitely. What you should have done is
var arr1 = "1,2,3,3,4,5,6".split(",");
for (var k = 0; k < arr1.length; k++) {
arr1[k] = +arr1[k];
}
console.log(arr1);
# [ 1, 2, 3, 3, 4, 5, 6 ]
Iterate only till the counter is lesser than length of the array. Otherwise store the length of the array in a temporary variable like this
for (var k = 0, len = arr1.length; k < len; k++) {
arr1[k] = +arr1[k];
}
You can write the same as, simply
console.log("1,2,3,3,4,5,6".split(",").map(Number));
# [ 1, 2, 3, 3, 4, 5, 6 ]

Categories

Resources