How to revert a simple JavaScript loop? - javascript

I'm learning basics of JavaScript. I try to code a program that logs the following scheme to the console:
*
* *
* * *
* * * *
* * * * *
* * * * *
* * * *
* * *
* *
*
I managed to get first half of the task by the code:
var x = 5;
var line;
for(var i = 0; i<x; i=i+1){
line = "";
for(var j=0; j<x; j=j+1){
if(j <= i){
line = line + " * ";
}
}
console.log(line);
}
So it looks like:
*
* *
* * *
* * * *
* * * * *
Could anybody give me a hint how to get the secod part of the scheme? I'd like to use another loop like the one I have but to revert it's action so that there would be less and less stars in each line.

Hints: You need to decrement i and j in the for loop and turn-around the <. instead of starting var i = 0 start at the end with 5.

With two for loops after another. The first one adds stars and the second one removes stars:
var line = "";
for (var i = 0; i < 5; i += 1) {
line += "*";
console.log(line);
}
for(var j = 5; j > 0; j -= 1) {
line = line.replace(line[j], "");
console.log(line);
}

spoiler:
What about just using a while loop?
var count = 0,
i = 1,
addition = 1,
str = null;
while (i) {
str = new Array(i+1).join('*');
console.log(str);
if (i === 5) {
console.log(str);
addition = -1;
}
i += addition;
}

You can, as one possible solution, put another if clause inside of your loop (read carefully):
If the line index reached half of the pyramid (maximum line length), start printing maximumLineLength * 2 - index - 1 instead.
This will essentially change the behaviour of the loop after the half is reached, so that the number of starts will start to decrease instead of increasing.
Another solution, if you're keeping the number of stars in the string, would be to add them until maxLineLength is reached, and then subtract them until you go back to 0 (you can use a boolean flag for that).
I'm not posting actual code to avoid spoiling the solution.

I think the solution with the conditionals and the one with the two loops are the ones you should use but you can compute the number of asterisks with a bit of modular arithmetic directly:
var x = 5;
var line;
for(var i = 1;i < x * 2;i++){
line = '';
for(var j = 0;j < Math.abs( (i+3) % 8 - 4) + 1;j++){
line = line + ' * ';
}
console.log(line);
}
I used a trick that will most probably be seen here as a little bit dirty but it works. The sequence I use here is 1,2,3,4,5,4,3,2 and to get the last 1 I just run it one more time.
In general:
To get a sequence from 1 to x and back to 1 again (with x > 1) run the outer loop x*2 times with Math.abs( (i+(x - 2)) % (2*x - 2) - (x - 1)) + 1 as the upper limit for the inner loop with i going from 1 to 2x-1.
Proof is left as an exercise for the student.

It's anti-pattern; why would you want this?
Nevertheless - accumulative variable:
var x = 5,
y,
line,
result = [];
while (x--) {
y = 5 - x;
line = '';
while (y--) {
line = line + '*';
}
result.push(line);
}
document.write(result.join('<br>'));
document.write('<br>');
document.write(result.reverse().join('<br>'));

Many solutions are possible but the simplest, like you suggest, is reverting the loop; this is what loop statement should look like:
for(var i = x-1 ; i>=0 ; i--)
Basically you have to change the for-loop conditions that will go backwards starting from the max-value , this is the first statement part and is called initializer ;
the loop must stop/break at 0 , second part of statement called test (until the loop satisfies this condition it will go on in next iteration );
the last part of statement is the iteration update (how the state should change in next loop);
that said changing the statement you should be able to keep your body unchanged :
var x = 5;
for (var i = x - 1; i >= 0; i--) {
line = "";
for (var j = 0; j < x; j = j + 1) {
if (j <= i) {
line = line + " * ";
}
}
console.log(line);
}

Related

How do I create an infinite addition output loop in JS/node?

I am new to JS. For fun I want to create an infinite loop that outputs the following way:
1+1=2, 2+2=4, 4+4=8, 8+8=16 and so on...This is what I have so far. I created a For loop to concise my theories/methods for practice, but I still can't get it to work properly.
for (let i = 0; i < 5; i++) {
num1 = i;
sum = i * 2;
answer = sum * 2;
console.log(sum + " + " + sum + " = " + answer * i);
}
At the moment you're just multiplying variables by two when really you want to take the result of adding two numbers together and use it in the next iteration.
Declare a step variable outside of the loop. On each iteration assign the the sum of two steps to an answer variable, log the result, and then assign answer to step.
let step = 1;
for (let i = 1; i < 10; i++) {
let answer = step + step;
console.log(`${step} + ${step} = ${answer}`);
step = answer;
}
Additional documentation
Template/string literals

JavaScript. Problems with a loop

Trying to create a piece of code that return all numbers below 1000 that are multiples of three. This is the relevant piece of code.
<script>
var i = 1;
var mplesOf3 = [0];
var myNum = 0;
while (myNum < 1000){
(3 * i) = myNum;
mplesOf3.push(myNum);
i++;
};
alert(mplesOf3);
</script>
The code runs in a html page, hence the style tags and alert.
The code basically trying to do 3x1 then 3x2 then 3x3 so on and so forth until the result is over 1000. I came up with the concept days ago and I'm still not sure why its not running properly.
For the record I've seen other solutions to how to do this but because I'm learning and want to improve I want to know why this solution doesn't work.
Thank you in advance
Edit: I should have known the mistake would be something stupid. I wrote (3 x 1) = n on the pseudocode and just didn't spot the mistake because nothing seem wrong to me. Thank to all parties, will accept an answer when I can.
Your JavaScript engine should be telling you you have a syntax error (look in the web console if you're using a browser). You can't have an expression like (3 * i) on the left-hand side of an assignment. In JavaScript, the thing on the right of the = is evaluated, and assigned to the thing on the left.
Your algorithm would also result in 1002 being pushed, because you're not testing the result of setting myNum = 3 * i until after pushing.
Sticking with your original algorithm but fixing those two things:
var i = 1;
var mplesOf3 = [0];
var myNum;
while ((myNum = 3 * i) < 1000){
mplesOf3.push(myNum);
i++;
} // Note: No semicolon here, you don't put semicolons after blocks
// attached to control-flow statements
console.log(mplesOf3);
This bit:
while ((myNum = 3 * i) < 1000){
evaluates 3 * i, assigns the result to myNum, and then checks that that value is < 1000.
That said, it would probably be simpler (fewer variables, less multiplication) to use a for and myNum += 3 in the increment section:
var mplesOf3 = [0];
var myNum;
for (var myNum = 3; myNum < 1000; myNum += 3) {
mplesOf3.push(myNum);
}
console.log(mplesOf3);
There's also no particularly good reason to special-case the 0 like that, so I'd probably leave it out of the array initially and start counting from 0:
var mplesOf3 = [];
var myNum;
for (var myNum = 0; myNum < 1000; myNum += 3) {
mplesOf3.push(myNum);
}
console.log(mplesOf3);
This is invalid:
(3 * i) = myNum;
Instead, do this:
myNum = (3 * i);
I would do it this way, and this takes care that even the last one stays below 1000:
<script>
var i, mplesOf3;
mplesOf3 = [];
for (i=0; i<1000; i++){
if (i % 3 === 0){
mplesOf3.push(i);
}
}
alert(mplesOf3);
</script>
Update (see comments):
For better efficiency your code is better, and here is a complete fix that even takes care of the last value to be below 1000:
var i = 1;
var mplesOf3 = [0];
var myNum = 0;
while (myNum < 1000){
myNum = 3 * i;
myNum < 1000 && mplesOf3.push(myNum);
i++;
};
alert(mplesOf3);
Another improvement would be to avoid the comparison in each loop and always remove the last item from the final array:
var i = 1;
var mplesOf3 = [0];
var myNum = 0;
while (myNum < 1000){
myNum = 3 * i;
mplesOf3.push(myNum);
i++;
};
mplesOf3.pop();
alert(mplesOf3);
maybe your mistake is (3 * i) = myNum;
you just need to: myNum=(3 * i);
First name then assign a value;

How do I calculate all prime numbers with a really large max in the browser using JSFiddle

I am working on some of the typical katas for JS and I came across one that wanted all the primes for a really large number. I tried the following in JSFiddle.
findPrimes(max){
let dont = [], primes = [];
for (var i = 2; i <= max; i++) {
if (!dont[i]) {
primes.push(i);
for (var j = i; j <= max; j += i) dont[j] = true;
}
}
}
This works relatively good till about this.findPrimes(51475143);, however, if I try say... this.findPrimes(851475143); I get a sad face an the JS engine appears to crash. I know I could probably do straight V8 and squeeze a bit out and maybe even go toward a C-based node module but to keep things simple I would like to keep it in the browser if possible. If not and proof can be provided I will accept that answer.
The problem you're having is likely due to running out of memory, with your dont array being the culprit. Luckily, since it's just an array of booleans, you can do the same thing with a bit array, which will save some space.
JavaScript doesn't have any native bit array type, but you can simulate one by storing an array of 32-bit numbers and using bitwise operators to retrieve or set the desired bit. So something like:
class BitArray {
constructor(len) {
this.arr = Array(Math.ceil(len / 32)).fill(0)
}
set(i) {
const j = Math.floor(i / 32)
this.arr[j] = this.arr[j] | (1 << (i % 32))
}
get(i) {
const j = Math.floor(i / 32)
return (this.arr[j] & (1 << (i % 32))) && 1 || 0;
}
}
Then, with that alone, you can run your snippet and get a result (although it takes a while):
class BitArray {
constructor(len) {
this.arr = Array(Math.ceil(len / 32)).fill(0)
}
set(i) {
const j = Math.floor(i / 32)
this.arr[j] = this.arr[j] | (1 << (i % 32))
}
get(i) {
const j = Math.floor(i / 32)
return (this.arr[j] & (1 << (i % 32))) && 1 || 0;
}
}
function findPrimes(max) {
const dont = new BitArray(max)
const primes = [];
for (var i = 2; i <= max; i++) {
if (!dont.get(i)) {
primes.push(i);
for (var j = i * 2; j <= max; j += i) dont.set(j);
}
}
return primes;
}
const primes = findPrimes(851475143);
console.log("Done. Max Prime:", primes[primes.length - 1])
console.log("And last 10 primes:", primes.slice(-10))
However, in addition to that, you can do a few more optimizations to your sieve:
You can start j at i*i instead of just i, since any number less than that will have a smaller prime than i as a factor already (and thus, will already have been set in dont).
You really only need to check odd numbers as part of the sieve, so you can change the outer loop to increment by 2 each time (i += 2 instead of i++), and then change the inner loop to increment by i*2 instead of i (since j + i*(odd) is always even).
Using those, you can change your snippet to:
class BitArray {
constructor(len) {
this.arr = Array(Math.ceil(len / 32)).fill(0)
}
set(i) {
const j = Math.floor(i / 32)
this.arr[j] = this.arr[j] | (1 << (i % 32))
}
get(i) {
const j = Math.floor(i / 32)
return (this.arr[j] & (1 << (i % 32))) && 1 || 0;
}
}
function findPrimes(max) {
const dont = new BitArray(max / 2) // Only need half the memory, since we only check odds.
const primes = [2]; // We already know 2 is prime
for (var i = 3; i <= max; i += 2) { // Start at 3, increment by 2, so only odds are checked.
if (!dont.get((i-1)/2)) { // The (i-1)/2 converts each odd to it's "halfway" number
primes.push(i);
for (var j = i*i; j <= max; j += i*2) dont.set((j-1)/2);
}
}
return primes;
}
const primes = findPrimes(851475143);
console.log("Done. Max Prime:", primes[primes.length - 1])
console.log("And last 10 primes:", primes.slice(-10))
As you can see, you get the same result for the last 10 primes, and, at least anecdotally, it seems to run quite a bit faster.

Fastest way to loop through this array in Javascript on Chrome 36

I have a very big array which looks similar to this
var counts = ["gfdg 34243","jhfj 543554",....] //55268 elements long
this is my current loop
var replace = "";
var scored = 0;
var qgram = "";
var score1 = 0;
var len = counts.length;
function score(pplaintext1) {
qgram = pplaintext1;
for (var x = 0; x < qgram.length; x++) {
for (var a = 0, len = counts.length; a < len; a++) {
if (qgram.substring(x, x + 4) === counts[a].substring(0, 4)) {
replace = parseInt(counts[a].replace(/[^1-9]/g, ""));
scored += Math.log(replace / len) * Math.LOG10E;
} else {
scored += Math.log(1 / len) * Math.LOG10E;
}
}
}
score1 = scored;
scored = 0;
} //need to call the function 1000 times roughly
I have to loop through this array several times and my code is running slowly. My question is what the fastest way to loop through this array would be so I can save as much time as possible.
Your counts array appears to be a list of unique strings and values associated with them. Use an object instead, keyed on the unique strings, e.g.:
var counts = { gfdg: 34243, jhfj: 543554, ... };
This will massively improve the performance by removing the need for the O(n) inner loop by replacing it with an O(1) object key lookup.
Also, avoid divisions - log(1 / n) = -log(n) - and move loop invariants outside the loops. Your log(1/len) * Math.LOG10E is actually a constant added in every pass, except that in the first if branch you also need to factor in Math.log(replace), which in log math means adding it.
p.s. avoid using the outer scoped state variables for the score, too! I think the below replicates your scoring algorithm correctly:
var len = Object.keys(counts).length;
function score(text) {
var result = 0;
var factor = -Math.log(len) * Math.LOG10E;
for (var x = 0, n = text.length - 4; x < n; ++x) {
var qgram = text.substring(x, x + 4);
var replace = counts[qgram];
if (replace) {
result += Math.log(replace) + factor;
} else {
result += len * factor; // once for each ngram
}
}
return result;
}

javascript generate a number of a variable length [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generating random numbers in Javascript in a specific range?
If I input a length of say 4, I need to get back a number between 0 9999.
And I want it to be 0 padded (0004), but that may be another function.
Try this:
function getNumber(range){
var max = Math.pow(10,range);
var num = Math.Random() * max;
}
As for the zerofill you're better off trying what Nathan suggested on his comment this
for(var x = 5, i = 0, y = ""; i < x​;​ ++i, y +​​= "9");
Math.floor(Math.random()*parseInt(y)); //random number
​
In the for loop, x would be your input length. You could move the definition of x outside the loop also if you needed.
You could also try this and see which one runs faster (probably the first one, fyi):
for(var x = 5, y = "", i = 0; i < x; ++i, y += Math.floor(Math.random()*9));
parseInt(y); //random number
function getRandom(c){
var r = (Math.random() * Math.pow(10, c)).toFixed(0);
while(r.length != c)
r = "0" + r;
return r;
}
getRandom(3);
Well, here's the number part. You can probably figure out the padding part.
function makeNumber(number){
var nines = "";
var returnNumber = "";
for(var i = 0; i < number; i++)
{
nines+= "9";
}
for(var i = 0; i < number; i++)
{
var returnNumber += String(Math.Random() * parseInt(nines));
}
return returnNumber;
}
Kind of sloppy but works:
var length = 4; //<-- or get however you want
var big = "";
for (i=0; i<length; i++) {
big = big + "9";
}
var big = parseInt(big);
var random = Math.floor(Math.random() * big).toString();
var random_len = random.toString().length;
if (random_len < length) {
var random_padded = random.toString()
padding = length - random_len;
for (i=0; i<padding; i++) {
random_padded = "0" + random_padded;
}
random = random_padded
}
alert(random);
Since it's javascript, you may want to take advantage of its weak typing in this scenario. One particular hackerish way of doing this is to generate n numbers between 0-9 and use string concatenation.
This post seems to have the answer: JavaScript expression to generate a 5-digit number in every case and you can pad with concatenation.
EDIT: so here is my implementation of it:
function random(x){
var rand = Math.floor(Math.random() * Math.pow(10,x));
var dummy = rand;
while (dummy<Math.pow(10,x-1)){
rand = "0" + rand;
dummy = dummy*10;
}
return rand;
}

Categories