Basic For Loop Logic Doesn't make sense to me - javascript

I've been trying to learn Javascript for the longest time, and it is kind of frustrating. I'm back to learning the basics again, and I was playing around with these for loops and arrays below.
Can someone please explain why the output of this code is [1,2,3,4,5] and not [6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]?
var game1 = new Array();
for(i = 25; i > "love is like a river".length; i = i - 1) {
console.log(game1.push(i));
}

console.log(game1.push(i));
What this statement does is it prints to the console the index of the element being pushed. The result 1,2,3,4,5 is the length of the array.
What you want to code is:
var game1 = [];
for(i = 25; i > "love is like a river".length; i--){
console.log(i);
game1.push(i);
}
in the above example I switched the declaration of the array, because this is the most common way(this is not necessary).It will still work normally with your version of declaration. In the for loop I've switched
i = i - 1;
to shorthand version:
i-- or --i
which decrements ' i ' by 1. Also I've separated
console.log(i) and game1.push(i) to be separate
this will print out the result of ' i ' : 25,24,23,22,21
this is because the for loop does the action that the users defines at the end of the loop, so when the loop prints out 21 and pushes it to the array, it decrements to 20, at which the loop stops. The array will still have the numbers 25,24,23,22,21. but the console will not log it.
if you want the output you defined above you would have to:
var game1 = [];
for(i = 6;i >= 25; i++){
game1.push(i);
console.log(game1[i-6]);
}
in this you add ' i ' to game1 resulting in [6,7,8,9,10,11,12,13,14...25] and you log the variable at the index of ' i - 6'. This will result in the number int he square brackets being "0,1,2,3,4,5" starting at 0 because that is where all arrays indexs start at.

The length property returns the length of a string (number of characters). In this way "love is like a river".length gives 20. I think you mistook it as no. of words. The loop will then behave like
var game1 = new Array();
for(i = 25;i>20;i=i-1){
console.log(game1.push(i));
}
To get your expected answer the code would be:
var game1 = new Array();
for(i = 25;i>"love is like a river".length;i=i-1){
console.log(game1.push(i));
}

You are getting the expected [25, 24, 23, 22, 21] as the result for game1!
The 1, 2, 3, … you are seeing are the results of the Array push calls that you are logging, which yield the length of the array each time.

The "love is like a river".length is 20. So the loop is equivalent to this:
for(i = 25; i>20; i=i-1){
}
That being said, you have 5 calls of the console.log passing to it the following arguments one at each for step:
game1.push(25)
game1.push(24)
game1.push(23)
game1.push(22)
game1.push(21)
Not knowing exactly what game1.push does, it's hard to tell. However, supposing that game1 is an array, you would get at each push the new length of the array.
According to MDN:
The push() method adds one or more elements to the end of an array and
returns the new length of the array.

"love is like a river".length is 20, so you will start from i=25 until i=21.
[1,2,3,4,5] represents the length of game1 for each loop.
To see the game1 value:
for(i=0; i<game1.length; i++) {
console.log(game1[i]);
}
Result: [25,24,23,22,21]

Lets start by breaking down your code, beginning with the new Array() constructor that you stored in the variable game1.
var game1 = new Array();
At this point, all you have is an empty array, which has been stored in a variable to be used at a later time. Incidentally, this is the equivalent of the array literal: var game1 = [].
Lets step through to the next portion of your code, which is a for() loop:
for (i = 25; i > "love is like a river".length; i--) {}
This loop initializes at the upper bound of 25 and decrements down to a lower bound bound of 20 which is set by the length() property condition of the string. Within this loop you have the statement:
console.log(game1.push(i));
The method push() adds an element or elements to the end of an array and returns the new length of the array to the stack. This method relies on the length property to determine its injection point. So, before the iteration, the game1 stack is currently at 0 since you never populated the array with any values. As you perform the iteration, push() method will add to the stack an undefined value on each step, there by increasing the array length by 1.
This can be illustrated by calling your game1 variable with a single numeric argument, which will set the initial size of the array. Here is an example:
var string = 'love is like a river';
var game1 = new Array(15);
for (i = 25; i > string.length; i--) {
console.log(game1.push(1));
}
As you can see, I passed the numeric argument 15 to the new Array() constructor which set the initial game1 length stack to 15. Since we are decrementing from 25 (i = 25) to 20 (string.length) we iterate 5 times, producing the expected result: [16, 17, 18, 19, 20].
If you are looking for an outcome of [6, 7, 8,...,25] you can can adjust your for() loop incrementing as opposed to decrementing and set the intitializer to 6. Here is what it will look like:
var s = "love is like a river";
for (i = 6; i <= s.length + 5; i++) {
console.log(i);
}

Related

Problem when learning forEach method in Javascript

I start learning Javascript since a week and I try to do some practice about the loop,
So I try to make a function which each time I call it, I doubled the numbers in an array.
I manage to do it with the classic "for" loop like this as an example:
var numbers = [2, 5, 37, 500, 75];
function getDoubled() {
for (var i = 0; i < numbers.length; i++) {
(numbers[i] = numbers[i] * 2);
}
}
So here the numbers in my array doubled each time I call the function getDoubled(); and now I try to do the same with forEach method.
var numbers = [2, 5, 37, 500, 75];
function getDoubled(array) {
array.forEach(function(number) {
(number = number * 2);
})
}
But I wasn't able to change the array when I call the function getDoubled(numbers), however if I test with console.log(number*2), it worked in the console, so I wasn't able to figure it out the mistake.
Reassigning an identifier has no side-effects. That is, doing someVariable = somethingNew will only result in a discernable change in how your script runs if something else references the someVariable which has the new value in it. Here, the number = number * 2 does nothing because nothing is referencing the doubled number variable; reassigning the parameter doesn't do anything to the array.
The way to do this with forEach would be to reassign the index in the array, just like in the for loop.
var numbers = [2,5,37,500,75];
function getDoubled(array) {
array.forEach(function(number, i){
array[i] = number * 2;
})
}
getDoubled(numbers);
console.log(numbers);
Alternatively, a nicer approach would be to construct a new array with the changed values, which can be done with .map, which creates a new array by performing a callback on every element of the original array - that way you don't have to look at the (unimportant) indicies to get the output you want.
var numbers = [2,5,37,500,75];
function getDoubled(array) {
return array.map(num => num * 2);
}
console.log(getDoubled(numbers));

Array OverWrite itself by pushing Objects (JavaScript)

So here comes my problem: In my opinion it's a very simple problem to solve but i don't know why this is happening; well as my title say my array is overwriting itself giving as output a 7 Object's Array
Here is the code, i've put some console.log() for you to see what i'm meaning:
let str = "100 23 20 99 92 123 88";
let arr = str.split(" ");
console.log(arr);
console.log("\n");
var aObj={};
let arrS=[];
console.log(arrS);
for (let i = 0; i<arr.length;i++){
let sum=0;
for (let j=0; j<arr[i].length;j++){
sum += parseInt(arr[i][j]);
}
aObj.value=sum;
aObj.strI=arr[i];
console.log(aObj);
console.log("\n");
arrS.push(aObj);
console.log(arrS);
console.log("\n");
}
https://repl.it/#Arcall95/try#index.js
Relevant: Push is overwriting previous data in array
Every iteration of the loop, what you're doing is changing the properties of a single object aObj and pushing it to arrS.
Instead, you should be creating a new object for each iteration by pulling var aObj={} inside the loop.

Array in Javascript (array.forEach Vs array.map) [duplicate]

I know that there were a lot of topics like this. And I know the basics: .forEach() operates on original array and .map() on the new one.
In my case:
function practice (i){
return i+1;
};
var a = [ -1, 0, 1, 2, 3, 4, 5 ];
var b = [ 0 ];
var c = [ 0 ];
console.log(a);
b = a.forEach(practice);
console.log("=====");
console.log(a);
console.log(b);
c = a.map(practice);
console.log("=====");
console.log(a);
console.log(c);
And this is output:
[ -1, 0, 1, 2, 3, 4, 5 ]
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
undefined
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
[ 0, 1, 2, 3, 4, 5, 6 ]
I can't understand why using practice changes value of b to undefined.
I'm sorry if this is silly question, but I'm quite new in this language and answers I found so far didn't satisfy me.
They are not one and the same. Let me explain the difference.
forEach: This iterates over a list and applies some operation with side effects to each list member (example: saving every list item to the database) and does not return anything.
map: This iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members (example: transforming list of strings to uppercase). It does not mutate the array on which it is called (although the callback function may do so).
References
Array.prototype.forEach() - JavaScript | MDN
Array.prototype.map() - JavaScript | MDN
Array.forEach “executes a provided function once per array element.”
Array.map “creates a new array with the results of calling a provided function on every element in this array.”
So, forEach doesn’t actually return anything. It just calls the function for each array element and then it’s done. So whatever you return within that called function is simply discarded.
On the other hand, map will similarly call the function for each array element but instead of discarding its return value, it will capture it and build a new array of those return values.
This also means that you could use map wherever you are using forEach but you still shouldn’t do that so you don’t collect the return values without any purpose. It’s just more efficient to not collect them if you don’t need them.
forEach()
map()
Functionality
Performs given operation on each element of the array
Performs given "transformation" on a "copy" of each element
Return value
Returns undefined
Returns new array with transformed elements, leaving back original array unchanged.
Preferrable usage scenario and example
Performing non-tranformation like processing on each element. For example, saving all elements in the database.
Obtaining array containing output of some processing done on each element of the array. For example, obtaining array of lengths of each string in the array
forEach() example
chars = ['Hello' , 'world!!!'] ;
var retVal = chars.forEach(function(word){
console.log("Saving to db: " + word)
})
console.log(retVal) //undefined
map() example
chars = ['Hello' , 'world!!!'] ;
var lengths = chars.map(function(word){
return word.length
})
console.log(lengths) //[5,8]
The main difference that you need to know is .map() returns a new array while .forEach() doesn't. That is why you see that difference in the output. .forEach() just operates on every value in the array.
Read up:
Array.prototype.forEach() - JavaScript | MDN
Array.prototype.map() - JavaScript | MDN
You might also want to check out:
- Array.prototype.every() - JavaScript | MDN
Performance Analysis
For loops performs faster than map or foreach as number of elements in a array increases.
let array = [];
for (var i = 0; i < 20000000; i++) {
array.push(i)
}
console.time('map');
array.map(num => {
return num * 4;
});
console.timeEnd('map');
console.time('forEach');
array.forEach((num, index) => {
return array[index] = num * 4;
});
console.timeEnd('forEach');
console.time('for');
for (i = 0; i < array.length; i++) {
array[i] = array[i] * 2;
}
console.timeEnd('for');
forEach: If you want to perform an action on the elements of an Array and it is same as you use for loop. The result of this method does not give us an output buy just loop through the elements.
map: If you want to perform an action on the elements of an array and also you want to store the output of your action into an Array. This is similar to for loop within a function that returns the result after each iteration.
Hope this helps.
map returns a new array.
forEach has no return value.
That's the heart of the difference. Most of the other answers here say effectively that, but in a much more convoluted way.
forEach() :
return value : undefined
originalArray : not modified after the method call
newArray is not created after the end of method call.
map() :
return value : new Array populated with the results of calling a provided function on every element in the calling array
originalArray : not modified after the method call
newArray is created after the end of method call.
Conclusion:
Since map builds a new array, using it when you aren't using the returned array is an anti-pattern; use forEach or for-of instead.
The difference lies in what they return. After execution:
arr.map()
returns an array of elements resulting from the processed function; while:
arr.forEach()
returns undefined.
one of the shuttle difference not mentioned here is that forEach() can loop over static (not live) NodeList while map() cannot
//works perfectly
document.querySelectorAll('.score').forEach(element=>console.log(element));
//Uncaught TypeError: document.querySelectorAll(...).map is not a function
document.querySelectorAll('.score').map(element=>console.log(element));
Diffrence between Foreach & map :
Map() : If you use map then map can return new array by iterating main array.
Foreach() : If you use Foreach then it can not return anything for each can iterating main array.
useFul link : use this link for understanding diffrence
https://codeburst.io/javascript-map-vs-foreach-f38111822c0f
Difference between forEach() & map()
forEach() just loop through the elements. It's throws away return values and always returns undefined.The result of this method does not give us an output .
map() loop through the elements allocates memory and stores return values by iterating main array
Example:
var numbers = [2,3,5,7];
var forEachNum = numbers.forEach(function(number){
return number
})
console.log(forEachNum)
//output undefined
var mapNum = numbers.map(function(number){
return number
})
console.log(mapNum)
//output [2,3,5,7]
map() is faster than forEach()
One thing to point out is that both methods skips uninitialized values, but map keeps them in the returned array.
var arr = [1, , 3];
arr.forEach(function(element) {
console.log(element);
});
//Expected output: 1 3
console.log(arr.map(element => element));
//Expected output: [1, undefined, 3];
Performance Analysis (again - not very scientific)
In my experience sometime .map() can be faster than .foreach()
let rows = [];
for (let i = 0; i < 10000000; i++) {
// console.log("here", i)
rows.push({ id: i, title: 'ciao' });
}
const now1 = Date.now();
rows.forEach(row => {
if (!row.event_title) {
row.event_title = `no title ${row.event_type}`;
}
});
const now2 = Date.now();
rows = rows.map(row => {
if (!row.event_title) {
row.event_title = `no title ${row.event_type}`;
}
return row;
});
const now3 = Date.now();
const time1 = now2 - now1;
const time2 = now3 - now2;
console.log('forEach time', time1);
console.log('.map time', time2);
On my macbook pro (late 2013)
forEach time 1909
.map time 444
.map and .forEach will do just about then same thing, until you start operating on arrays with millions of elements. .map will create another collection with the same size (and possibly type, depending on the array species) which could use up a LOT of memory. .forEach will not do this.
const arr = [...Array(100000000).keys()];
console.time("for");
for (let i = 0; i < arr.length; i++) {}
console.timeEnd("for");
console.time("while");
let j = 0;
while (j < arr.length) {
j++;
}
console.timeEnd("while");
console.time("dowhile");
let k = 0;
do {
k++;
} while (k < arr.length);
console.timeEnd("dowhile");
console.time("forEach");
arr.forEach((element) => {});
console.timeEnd("forEach");
VM35:6 for: 45.998046875 ms
VM35:13 while: 154.581787109375 ms
VM35:20 dowhile: 141.97216796875 ms
VM35:24 forEach: 776.469970703125 ms
Map implicitly returns while forEach does not.
This is why when you're coding a JSX application, you almost always use map instead of forEach to display content in React.

Learning While Loops. Can't figure out what I am missing in my code.

Write a function called indexToString. This function should:
1. Take an array as an argument
2. Create and return a new array of all passed array elements as strings
3. Each strings should be formatted like so: “[index] is [element at index]”
This is the error I am getting: returns an array of passed-in array elements as strings with element index specified
expected undefined to deeply equal [ '0 is 1', '1 is 2', '2 is 3' ]
Here is my code:
var indexToString = function(array){
index = 0;
elementAtIndex = 0;
var i = 0;
while(i < array.length){
console.log(index + " is " + elementAtIndex);
i++
}
return array[i];
};
Two Three errors.
Firstly, the while loop will exit when i is no longer less than array.length; the first such number is array.length. This means, at the end of the loop, array[i] is array[array.length], which is just outside the array, thus undefined.
Secondly, you are supposed to return an array of strings, as told by your test failure message; not print them to the console.
EDIT: Thirdly, what Spencer said. :) Use i instead of index, and array[i] instead of elementAtIndex.
You want to start with an empty array outside the loop, and push each string you construct into it; then return that array after the loop.
Or you can do it with "new" JavaScript:
var indexToString = array => array.map((e, i) => `${i} is ${e}`)
You should reflect a bit more on your code, it is quite nonsense so far.
Let's decompose the question to identify what should be done:
Write a function called indexToString. This function should:
Take an array as an argument
Create and return a new array of all passed array elements as strings
Each strings should be formatted like so: “[index] is [element at index]”
So:
you create a function called indexToString which body contains the code, as you did.
In the initialization part before your while, you should create a new empty array that is going to be filled, and declare an integer called index for example initialized at 0 that is going to be used to loop through the original array. (Tip: var new_array = []; to create, and use new_array.push(elem); to append an element)
in your while, you should push at the end of your new array a string built as follow: "["+index+"] is ["+array[index]+"]" AND you should increment your index. You loop while(index < array.length).
At the end, you can return the new array !
Good luck with learning programming!
If the arraylenth is 10, the function will return array[10].This is an array-bound.
When you enter the last loop, the i becomes equal to array.length, so array[i] is undefined after this. But probably this is not what you wanted. you want to return the full array.
var indexToString = function(array){
var new_array = [];
var i = 0;
while(i < array.length){
new_array[i] = i + " is " + array[i];
i++;
}
return new_array;
};
console.log(indexToString([1,2,3]));

Losing the logic in my Javascript program

I have an issue with Javascript. I want to make the program , which generates 6 random numbers ( from 1 to 49 ).Anyway im doing it with for loop and it works. But when I try to find if any of those 6 numbers has a duplicate number , to replace it with a new random number. I've looked at js array duplicate functions , Im applying it , but it seems my fault is in the logic , still beginner with js , so please help me :)
js code:
var arr = new Array(7);
var numbers = [];
for(var i=1; i<arr.length;i++){
numbers[i] = Math.floor(Math.random()*48)+1;
if(numbers[i] == numbers[i+1]){
arr.indexOf(numbers[i]);
arr.push(Math.floor(Math.random()*48));
}
}
i`m trying to apply indexOf ( to find the duplicate number's index, and after that to replace it with new element via push()). Please give me some advises how to improve on my programming logic skills :(
First, JavaScript arrays are zero-indexed, so the first index is 0, not 1. Although it is valid to skip the first index and use the second to seventh indices instead, you will usually want to avoid that.
Second, why do you check numbers[i] against numbers[i + 1]? At that point, numbers[i + 1] won't have been set yet as it will be set in the next iteration. Additionally, even if this problem did not exist, your code would fail to catch this sequence: [ 5, 3, 5 ].
Third, I am not quite sure why you use two different arrays. Although you definitely can, there is no good reason to do so.
I will suggest another way to solve your problem and add comments to the steps necessary. I hope these will help you to understand this solution to your problem.
// Create an array for the chosen numbers
var numbers = [];
// Loop to generate 6 elements, zero-based
for(var i = 0; i < 6; i++) {
// This variable will hold the number we choose
var number;
// This is a do-while loop which generates a random integer
do {
// Generate a random integer between 1 and 49 (incl.)
number = Math.floor(Math.random() * 48) + 1;
} while(numbers.indexOf(number) != -1); // Exit loop once the number is not contained in the array
// Store the number in the array
numbers[i] = number;
}
This algorithm is short (8 SLOC) and pretty efficient.
This is one way you could do it:
var numbers = [];
for(i=0;i<6;i++){
numbers[i] = Math.floor(Math.random()*48)+1;
//this loop will help us check all of the already assigned numbers.
for(x=0;x<i;x++){
if(numbers[x] == numbers[i]){
i--;
}
}
}
This might not be the most efficient and optimal way to do it, but it sure works and it will give you no repetition on the numbers now that it will loop untill it finds a different number. Its a fast and short solution, yet not the most efficient. Hope this helps =).
for (var a=[],i=1;i<40;++i) a[i]=i;
function shuffle(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
a = shuffle(a);
Random Numbers , No repeats
This statement will never be true:
if(numbers[i] == numbers[i+1]){
When you start, numbers array is empty. Then you assign one random to element 0. Then you try to compare element 0 in numbers to 1, but numbers[1] will be undefined.
The best way to do this is to start with an empty arr array, meaning length of 0. Loop until length equals 6. In the loop, generate a random number and only push the value into the arr array if the number doesn't exist in there.
UPDATE:
After seeing some of the answers, I think this is probably the simplest:
var arr = [],
num;
while (arr.length < 6) {
num = Math.floor(Math.random() * 48) + 1;
if (arr.indexOf(num) === -1) {
arr.push(num);
}
}
console.log(arr);

Categories