How can I optimize (or improve) this Fizz Buzz script? - javascript

//Script to find numbers that are the power of 3 and 5 from 1 to 100 using % Modulus operator - when it finds a number that can be the power of 3 or 5 it outupts FizzBuzz... example hosted on my blog http://chadcollins.com/find-numbers-that-are-the-power-of-3-and-5-from-1-to-100/
// this was an interview question, and I want to know how to optimize or improve this with "pure javascript".
<div id=out_put></div>
//from a list of 1 to 100 numbers, find the 3's and 5's using modulus
function findPowerOf(numList) {
//setup the variables
var myModMatch1 = 3; //find numbers that have the power of 3
var myModMatch2 = 5; //find numbers that have the power of 5
var tempCheck1 = ""; //stores true or false based on myModMatch1
var tempCheck2 = ""; //stores true or false based on myModMatch2
var stringOut = ""; //concat string for output
var numListStart = 1; //starting number list index
var numListFinish = 100; //ending list index
var numberList = []; //create the list of numbers
for (var i = numListStart; i <= numListFinish; i++) {
numberList.push(i);
}
for (i = 0; i < numberList.length; i++) { //loop on each number and check the modulus params
console.log(numberList[i]);
if ((numberList[i] % myModMatch1) === 0) { //check first modulus param
console.log('houston, we have a match on a number modulus 3');
tempCheck1 = "Fizz";
}
if ((numberList[i] % myModMatch2) === 0) {
console.log('houston, we have a match on a number modulus 5');
tempCheck2 = "Buzz";
}
if (tempCheck1 === "" && tempCheck2 === "") { //no modulus matches
console.log("no modulus matches");
stringOut += numberList[i] + "\n";
}
stringOut += tempCheck1 + tempCheck2 + "\n";
tempCheck1 = ""; //clear both variables
tempCheck2 = "";
}
//dynamically make a div
var outDiv = document.createElement("div");
outDiv.innerHTML = stringOut; //output the final loop values all at once
document.getElementById('out_put').appendChild(outDiv); //update the view
}
findPowerOf(); // call our function

You can remove pretty much all the variables and the function parameter (especially since you're not using the parameter at all). That will also remove one redundant loop.
You can optimize those three parallel ifs by doing one nested if-else.
With all that, you could reduce the code to about 30% of its current size.
Let me give it a shot:
My optimized version:
var div = document.getElementById('out_put');
for (var i = 1; i <= 100; i++) {
if (i % 3 == 0 || i % 5 == 0) {
if (i % 3 == 0) {
div.innerHTML += "Fizz";
}
if (i % 5 == 0) {
div.innerHTML += "Buzz";
}
} else {
div.innerHTML += i;
}
div.innerHTML += '<br>';
}
<div id=out_put></div>
I've used one variable for the div element because selecting it on every iteration is a waste of resources.
Shorter/less readable version:
Here's an even shorter, commented and slighly less-readable version:
var div = document.getElementById('out_put');
for (var i = 1; i <= 100; i++) {
if (i % 3 == 0 || i % 5 == 0) { // see if there's ANY match
if (i % 3 == 0) // check for 3
div.innerHTML += "Fizz";
if (i % 5 == 0) // check for 5
div.innerHTML += "Buzz";
} else // otherwise just output the number
div.innerHTML += i;
div.innerHTML += '<br>'; // add a new line after each
}
<div id=out_put></div>
Insane version - one-liner:
(just for fun - don't ever do this!)
And if you really REALLY want to go crazy with this, you can do a few nested ternary conditionals inside the loop. Technically, a loop with a single line inside - but pretty much unreadable and will perform worse because I removed the DOM element reference variable, so it will do the element query on every iteration. :)
for (var i = 1; i <= 100; i++)
document.getElementById('out_put').innerHTML += ( (i % 3 == 0 || i % 5 == 0) ? ( ((i % 3 == 0) ? "Fizz" : "") + ((i % 5 == 0) ? "Buzz" : "") ) : i) + '<br>';
<div id=out_put></div>

Related

Why code works when I write myArray[i] and not when I save myArray[i] in a variable?

I want to populate an empty array with the classical fizzbuzz game (numbers from 1 to 100, when a number is divisible by 3 print 'Fizz, divisible by 5 print 'Buzz', divisible by both 3 and 5 print 'Fizzbuzz'). The problem is, when I write code like in the first portion of code below saving my array[i] in a more convenient variable my if-else if statement doesn't work, only normal numbers are printed; but when I use array[i] instead of a variable everything works fine, as you can see in the second portion of code, where 'Fizz', 'Buzz', 'FizzBuzz' overwrite the normal numbers. They should be the same thing right?
First portion of code with a variable instead of array[i]
var numberArray = [];
var number = 0
for (var i = 0; i < 100; i++) {
number += 1;
thisNumber = numberArray[i];
numberArray.push(number);
if (number %3 ==0 && number %5 ==0) {
thisNumber = 'FizzBuzz';
} else if ( number %3 ==0 ) {
thisNumber = 'Fizz';
} else if ( number %3 ==0 ) {
thisNumber = 'Buzz';
}
}
console.log(numberArray);
Second portion of code with array[i] instead of a variable
var numberArray = [];
var number = 0
for (var i = 0; i < 100; i++) {
number += 1;
numberArray.push(number);
if (number %3 ==0 && number %5 ==0) {
numberArray[i] = 'FizzBuzz';
} else if ( number %3 ==0 ) {
numberArray[i] = 'Fizz';
} else if ( number %3 ==0 ) {
numberArray[i] = 'Buzz';
}
}
console.log(numberArray);
Reassigning a variable, by itself, never has any side effects (except in the most rare situations which aren't worth worrying about). Doing thisNumber = 'FizzBuzz'; does not change anything about how thisNumber may have happened to be used in the past.
Push after assigning to thisNumber. You also want to push thisNumber, not number.
You also need to change the final % 3 to % 5 - you're currently testing % 3 twice.
var numberArray = [];
for (var i = 0; i < 100; i++) {
let thisNumber = i;
if (i % 3 == 0 && i % 5 == 0) {
thisNumber = 'FizzBuzz';
} else if (i % 3 == 0) {
thisNumber = 'Fizz';
} else if (i % 5 == 0) {
thisNumber = 'Buzz';
}
numberArray.push(thisNumber);
}
console.log(numberArray);
In JavaScript a variable is just a reference to an object and an assignment changes where it points to. In
thisNumber = 'FizzBuzz';
you create a new string object and reference it with thisNumber. In
numberArray[i] = 'FizzBuzz';
you modify the i-th element of the array numberArray.
You can't create a reference to an array element and modify it with an assignment. That's not possible in JavaScript.

Javascript conditional statement not executing

I'm attempting to make a function that builds a checker board however I can't get my second conditional statement to execute and create a new line.
function grid(size) {
var board = "";
for (i = 0; i <= (size * size); i++) {
if (i % 2 === 0) {
board += ' ';
} else if (i % size === 0) {
board += "\n";
} else {
board += '#';
}
}
console.log(board);
}
grid(8);
It appears the else if statement is not executing because I've tried changing the '\n' and condition to other things but nothing is printed. This question is from Eloquent Javascript and the given solution is this:
var size = 8;
var board = "";
for (var y = 0; y < size; y++) {
for (var x = 0; x < size; x++) {
if ((x + y) % 2 == 0)
board += " ";
else
board += "#";
}
board += "\n";
}
console.log(board);
I'm not sure why the second one works but mine doesn't.
Let´s analyse your code:
if(i % size === 0)
This means, when i is equal to 0 or is a multiple of size. In your case, size is 8.
So for your if to trigger, i should be 0,8,16,32....
In all this cases, it will never fire because when i is 0,8,16,32... i % 2 is 0, so it will run the first if instead and never the second one. You should inverse the order of the ifs or run both
i % 2 will always execute instead of i % (8 * 8). You should swap their order or remove the else from the second if.

javascript: summing even members of Fibonacci series

Yet Another (Project Euler) Fibonacci Question: Using (vanilla) javascript, I'm trying to sum the even numbers <= a given limit:
First, something is wrong with my 'if' statement, as some of the results (below) are wrong:
function fibonacciSum(limit) {
var limit = limit;
var series = [1,2];
var sum = 0;
var counter = 0;
for (var i=1; i<=33; i++) { // 33 is arbitrary, because I know this is more than enough
var prev1 = series[series.length-1];
var prev2 = series[series.length-2];
var newVal = prev1+prev2;
series.push(newVal);
counter ++;
console.log("series "+ counter + " is: " + series);
if (series[i] % 2 === 0 && series[i] <= limit) { // intending to sum only even values less than/equal to arbitrary limit
// sum = sum + series[i];
sum += series[i];
}
/*
var sum = series.reduce(function(a,b) {
/*
possible to filter here for even numbers? something like:
if (a %2 === 0)
*/
return a+b;
});
*/
console.log("SUM " + counter + ": " + sum);
} // for loop
} // fibonacci
fibonacciSum(4000000);
Results:
series 1 is: 1,2,3
SUM 1: 2
series 2 is: 1,2,3,5
SUM 2: 2
series 3 is: 1,2,3,5,8
SUM 3: 2 // looking for a '10' here
series 4 is: 1,2,3,5,8,13
SUM 4: 10
series 5 is: 1,2,3,5,8,13,21
SUM 5: 10
series 6 is: 1,2,3,5,8,13,21,34
SUM 6: 10 // looking for '44' here
Can someone please explain why neither of these working as intended?
if (series[i] % 2 === 0) { ...
... or
if (series[i] % 2 === 0 && series[i] <= limit) { ...
And secondly, as you can see I had also tried to use series.reduce(... but I can't figure how to sum only the even values; is that doable/cleaner?
Thank you,
Whiskey T.
No need for arrays. Use three variables for let's say previous, current and next numbers in fibonacci sequence.
We can also begin the sequence with 2 an 3 because there are no other even numbers that will affect the result.
We initialize the sum of even numbers with 2 because it's the current number and it's even. In a do...while we advance with the numbers in sequence and if the new numbers are even we add them to the sum. Stop when limit is reached.
function fibEvenSum(limit) {
var prev = 1,
current = 2,
next;
var sum = 2;
do {
next = prev + current;
prev = current;
current = next;
if (current >= limit)
break;
if (current % 2 == 0)
sum += current;
} while (true)
return sum;
}
This algorithm can be improved using properties of odd and even numbers:
odd + odd = even
even + even = even
even + odd = odd
This should work for you...
var fibonacciSum = function(limit) {
var nMinus2 = 1, nMinus1 = 2, evensFound = [2], sum = nMinus1;
while (sum <= limit){
var n = nMinus1 + nMinus2;
if (n % 2 == 0){
sum += n;
if (sum > limit){
break;
}
evensFound.push(n);
}
nMinus2 = nMinus1;
nMinus1 = n;
}
console.log("Evens found - " + evensFound);
return evensFound;
};
var evensFound1 = fibonacciSum(4),
evensFound2 = fibonacciSum(10),
evensFound3 = fibonacciSum(60),
evensFound4 = fibonacciSum(1000);
$(evenResults).append(evensFound1
+ "<br/>" + evensFound2
+ "<br/>" + evensFound3
+ "<br/>" + evensFound4);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="evenResults"></div>
A solution in the spirit of the one your attempted — with arrays — though as pointed out, they are not necessary.
var i = 0, sequence = [1, 2], total = 0;
while (sequence.slice(-1)[0] < 4000000) {
sequence.push(sequence.slice(-1)[0] + sequence.slice(-2)[0]);
}
for ( i; i <= sequence.length; i++ ) {
if ( sequence[i] % 2 === 0 ) {
total += sequence[i];
}
}

transform every 3rd letter to uppercase

how to transform every 3rd character to uppercase. for example this string pifedvcbtauzkwgnxyjrhmq converted into piFedVcbTauKkwGnxYjrHmq.
here is what i've done so far
function up3rdletter(str){
var i, result = '';
for(i = 0; i < str.length; i++){
if(i > 0 && i % 3 == 0){
result += str[i].toUpperCase();
}else{
result += str[i];
}
}
return result;
}
the script above return pifEdvCbtAuzKwgNxyJrhMq, it start converting from 4th letter. if I change the modulo number to 2 it become piFeDvCbTaUzKwGnXyJrHmQ
It's rather trivial: indexing in JS starts from 0, but you want to change letters based on 1-based index, natural for human beings. ) Solution? Either shift the remainder check:
result += i % 3 === 2 ? str[i].toUpperCase() : str[i];
... or go on checking against 0, but advance i instead:
result += (i + 1) % 3 ? str[i] : str[i].toUpperCase();
But actually, I'd probably write it as follows:
result = str.replace(/(..)(.)/g, function(_, m1, m2) {
return m1 + m2.toUpperCase();
});
function up3rdletter(str){
var i, result = '';
var counter = 1;
for(i = 0; i < str.length; i++){
if(i > 0 || counter % 3 == 0){
result += str[i].toUpperCase();
}else{
result += str[i];
}
counter++;
}
return result;
}

Insert dashes into a number

Any ideas on the following? I want to input a number into a function and insert dashes "-" between the odd digits. So 4567897 would become "456789-7". What I have so far is to convert the number into a string and then an array, then look for two odd numbers in a row and use the .splice() method to add the dashes where appropriate. It does not work and I figure I may not be on the right track anyway, and that there has to be a simpler solution.
function DashInsert(num) {
var numArr = num.toString().split('');
for (var i = 0; i < numArr.length; i++){
if (numArr[i]%2 != 0){
if (numArr[i+1]%2 != 0) {
numArr.splice(i, 0, "-");
}
}
}
return numArr;
}
The problem is you're changing the thing you're iterating over. If instead you maintain a separate output and input...
function insertDashes(num) {
var inStr = String(num);
var outStr = inStr[0], ii;
for (ii = 1; ii < inStr.length; ii++) {
if (inStr[ii-1] % 2 !== 0 && inStr[ii] % 2 !== 0) {
outStr += '-';
}
outStr += inStr[ii];
}
return outStr;
}
You can try using regular expressions
'4567897'.replace(/([13579])(?=[13579])/g, '$1-')
Regex Explained
So, we find an odd number (([13579]) is a capturing group meaning we can use it as a reference in the replacement $1) ensure that it is followed by another odd number in the non-capturing positive lookahead ((?=[13579])) and replace the matched odd number adding the - prefix
Here is the function to do it:
function dashes(number){
var numString = '';
var numArr = number.toString().split('');
console.log(numArr);
for(i = 0; i < numArr.length; i++){
if(numArr[i] % 2 === 1 && numArr[i+1] % 2 === 1){
numString += numArr[i] + '-';
}else{
numString += numArr[i];
}
}
console.log(numString);
}
dashes(456379);
Tested and everything.
Edit: OrangeDog's answer was posted earlier (by nearly a full half hour), I just wanted to make an answer which uses your code since you're almost there.
Using another array instead of splicing into one you were looping through (this happens to return a string using join):
var num = 4567897;
function DashInsert(num) {
var numArr = num.toString().split('');
var len = numArr.length;
var final = [];
for (var i = 0; i < len; i++){
final.push(numArr[i]);
if (numArr[i]%2 != 0){
if (i+1 < len && numArr[i+1]%2 != 0) {
final.push("-")
}
}
}
return final.join("");
}
alert(DashInsert(num));
function dashInsert(str) {
var arrayNumbers = str.split("");
var newString = "";
for (var i = 0; i < arrayNumbers.length; i++){
if(arrayNumbers[i] % 2 === 1 && arrayNumbers[i + 1] % 2 === 1){
newString = newString + arrayNumbers[i] + "-";
} else {
newString = newString + arrayNumbers[i];
}
}
return newString;
}
var result = dashInsert("3453246");
console.log(result);

Categories

Resources