How javascript(ECMAScript) assignment operator works - javascript

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();

Related

JavaScript reversing array

function reverseArrayInPlace(array) {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
let old = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = old;
}
return array;
}
let arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]
I am working on the Data Structures of the book Eloquent JavaScript. I mostly understand how this loop works which is cutting the array in half and then start swapping elements at the opposite sides.
but here my problem: the first round of the loop my understanding of "array[i]" is at index 0 and "Math.floor(array.length / 2)" is at index 1. So, we set old = index 0 and then override it to "array[array.length - 1 - i]". the question is first what exactly does -i part mean and what index does this "array[array.length - 1 - i]" located at at the first round of the loop. please someone explain it to I am very visual and I can't pass it if I don’t see each statement in action.
array.length - 1 - i is at the first round array.length - 1 - 0 which is the last element in the array.
So the loop swaps the first and the last element, then increments i. Next round the 2nd and the value before the last one is going to be swapped and so on.
Array: 1234567890
1st Iteration i=0: ^ ^
2nd Iteration i=1: ^ ^
3rd Iteration i=2: ^ ^
4th Iteration i=3: ^ ^
5th Iteration i=4: ^^
easier to understand, and without the problem with odd arr.length
function reverseArrayInPlace(arr)
{
for (let i= 0, j= arr.length -1; i < j; i++, j--)
{
// swapp values of arr[i] and arr[j]
[ arr[i], arr[j] ] = [ arr[j], arr[i] ];
}
return arr;
}
let arrayValues = [1, 2, 3, 4, 5];
reverseArrayInPlace( arrayValues );
document.write( JSON.stringify( arrayValues ));
An array is zero-indexed. Meaning, the first item in an array is at the [0] position. When you use array.length, it returns a total of array elements which can be confusing to you because an array of length 5 will have it's last element located at array[4] (because zero is the first).
For each iteration in your function, it uses the counter i to find the position at the end of the array that matches the iteration.
array.length - 1 - i
The -1 part is explained above. When using array.length, you have to subtract 1 to get the actual position.
I find the following approach helpful for working out what a loop is doing. You start with the array 1,2,3,4,5. Each iteration of the loop has two steps which change the array. The result of each step acting on the array are shown under 1st Step and 2nd Step below. Also shown is the value of i for the loop and the value of old for the loop.
i old 1st Step 2nd Step
0 1 5,2,3,4,5 5,2,3,4,1
1 2 5,4,3,4,1 5,4,3,2,1
1st Step: array[i] = array[array.length - 1 - i];
2nd Step: array[array.length - 1 - i] = old;
Using two indexes into the array, one increasing from 0, the other decreasing from array.length-1, and with a destructuring swap, reverse can be stated a little more concisely like this...
function reverseArrayInPlace(array) {
for (let i=0, j=array.length-1; i<j; i++, j--)
[array[i], array[j]] = [array[j], array[i]];
return array;
}
let arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]

Filtering arrays of complex objects with loops

I have two arrays of complex nexted objects that I'm looking for qualifying values within using loops and if statements as seen below. When I find a qualifying object, I need to filter that object out during the next go around of the loop. I'm trying to do that with an array as you can see here but it isn't working as the array starts over during each iteration of the loop. The following version is a simplified version of my code.
I want to update the values in array2 based on the if statement so that those values are not repeated in the nested loop. Instead my emptyArray remains empty instead of adding values from the array2 as elements of array2 are equal to elements of array.
To be clear, right now emptyArray remains empty and never filters array2. I'd like to see emptyArray collect value 2 at the start of the outer loop's second iteration then I'd like to see emptyArray collect value 4 at the start of the 4th iteration of the outer loop.
I'd want to filter each of these values from array2 as they become part of emptyArray so that they do not set off the if statement during the 6th and 8th iterations of the outer loop. I imagine that emptyArray = [2, 4] and array2 = [6, 8, 10] when the loops are finished.
Bottom line, I need emptyArray to collect the qualifying values and pass them back to var array2 for filtering as the loop processes. Remember this is a simplified version of the arrays, and underscore based solution would be very complicated for me to implement or for you to successfully suggest without much more detail.
My code:
var array = [1, 2, 3, 4, 1, 2, 3, 4];
var array2 = [2, 4, 6, 8, 10];
var emptyArray = [];
for (i = 0; i < array.length; i++){
var something = array[i];
var array2 = _.without(array2, emptyArray);
for (a = 0; a < array2.length; a++){
var value = array2[a];
if(something === value){
emptyArray.push(value);
break;
}
}
}
There are a few things wrong with your code, but the reason why you think that push isn't working is because you are overriding your array2 inside the loop.
The push never gets called because your for loop sees an empty array2 when you are doing var array2 = _.without(array2, emptyArray);
Basically var array2 = _.without(array2 /* this is empty, you just overrode it in this scope */, emptyArray); will always result in an empty array and your for loop will exit because length is array2.length === 0 from the start.
Also, you want to use _.difference instead of _.without
var array = [1, 2, 3, 4, 1, 2, 3, 4];
var array2 = [2, 4, 6, 8, 10];
var emptyArray = [];
for (var i = 0; i < array.length; i++) {
var something = array[i];
array2 = _.difference(array2, emptyArray);
for (var j = 0; j < array2.length; j++) {
var value = array2[j];
if (something === value) {
emptyArray.push(value);
break;
}
}
}
console.log("array2",array2);
console.log("emptyArray", emptyArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.js"></script>
array2 [6, 8, 10]
emptyArray [2, 4]
var array = [1, 2, 3, 4, 1, 2, 3, 4];
var array2 = [2, 4, 6, 8, 10];
var emptyArray = [];
for (var i = 0; i < array.length; i++) {
var something = array[i];
for (var j = 0; j < array2.length; j++) {
var value = array2[j];
if (something === value) {
array2 = _.without(array2, value);
break;
}
}
}

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 ]

Javascript 2D array generation, "strange" behavior

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

Javascript Array.push method issue

I have the following code:
function build_all_combinations(input_array){
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0]
array.push(push_value)
console.log(array)
combo.push(array)
}
console.log(combo)
}
Which outputs:
[2, 3, 1]
[3, 1, 2]
[1, 2, 3]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
The last line should be: [[2, 3, 1],[3, 1, 2],[1, 2, 3]]
I'm obviously not grokking something about the way the array is working. Each individual array is correct, but when I go to push them to the combo array, something is failing along the way. What is it?
Each time you are pushing the same array into the combo array; ie, all the references are pointing to the same instance in memory. So when you update one, you've in reality updated them all.
If you want separate references, you'll need to create separate arrays.
shift and slice are your friends here:
var array = [1,2,3];
var combo = []
for(var i = 0; i<array.length; i++){
array.push(array.shift()); // remove first element (shift) and add it to the end (push)
combo.push(array.slice()); // add a copy of the current array to combo
}
DEMO
jordan002 has given the explanation for this behaviour.
Here's the workaround.
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0];
array.push(push_value);
console.log(array);
combo.push(array.concat([]));
}
console.log(combo);
You can store a copy in temp variable.
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0];
array.push(push_value);
console.log(array);
var temp = array.slice();
combo.push(temp);
}
console.log(combo)
Reference

Categories

Resources