Javascript: getting rid of nested loop - javascript

It's been a while since I wrote any Javascript. Is there a more elegant way to do this. Specifically want to get rid of the second loop:
<script>
var number = 0;
for (var i=1; i<11; i++) {
for (var x=1; x<11; x++) {
if (i==1) {
number = x;
} else {
number = Math.pow(i, x);
}
document.write(number + " ");
if (x == 10) {
document.write("<br>");
}
}
}
</script>

I would stick with 2 loops but i would change one if statement and move it after the 2nd loop and avoid document.write and insert it all at once to reduce the number of time you change the DOM
let result = ''
for (let i = 1; i < 11; i++) {
for (let x = 1; x < 11; x++)
result += (i==1 ? x : Math.pow(i, x)) + ' '
result += '<br>'
}
document.body.insertAdjacentHTML('beforeend', result)
Edit If you really don't want the 2nd loop:
let result = ''
// you must swap the condition to check for x instead of i
for (let i = 1, x = 1; x < 11; i++) {
result += (x==1 ? i : Math.pow(x, i)) + ' '
// and reset i and increase x yourself
if (i == 10) {
i = 0
x++
result += '<br>'
}
}
document.body.insertAdjacentHTML('beforeend', result)
Edit2 just for the fun: No for loops.
Just a recursive function :P
function build(i = 1, x = 1, res = '') {
res += (x == 1 ? i : Math.pow(x, i)) + ' '
i == 10 ? (x++, i=1, res += '<br>') : i++
return x == 11 ? res : build(i, x, res)
}
document.body.insertAdjacentHTML('beforeend', build())

In terms of 'elegancy', I'd go for for... in loops or map function. That doesn't solve your nested loop though.
On a side note, nested loops are not necessarily bad. If that's the correct way to implement the specific algorithm, then that's how it is.

Using Math.pow() is un-necessary overhead. Nested loops are not necessarily bad.
var number = 0;
for (var i=1; i<11; i++) {
document.write(i + " ");
number = i;
for (var x=2; x<11; x++) {
number = (i == 1) ? x : number * i;
document.write(number + " ");
}
document.write("<br>");
}

Another way of doing it with 1 loop only, tho not as clean:
var number = 0;
var x = 1;
var calc = 0;
var calcx = 1;
var increment = false;
for (var i=1; i<101; i++) {
increment = false;
calc = i % 10;
if(calc == 0){
calc = 10;
increment = true;
}
if (calcx==1) {
number = calc;
} else {
number = Math.pow(calcx, calc);
console.log(calcx+" "+calc);
}
document.write(number + " ");
if (i % 10 == 0) {
document.write("<br>");
}
if(increment){
calcx++;
}
}

Here's another way with only one loop:
[...Array(100)].map((_,i) => {
document.write(((i>9)?Math.pow(Math.floor((i+10)/10),(i%10)+1):i+1) + ' ' + ((i%10==9)?'<br>':''));
});

Related

How to write a number pattern generator program in JavaScript?

I have to make a pattern like this:
=========1=========
=======22122=======
====33322122333====
4444333221223334444
I have not found the logic yet. I tried to code it, but the output is different.
Here is the output of my working code snippet:
----1-----
---123----
--12345---
-1234567--
123456789-
function nomor3(input){
let temp = '';
for (let x = 1; x <= input; x++){
for (let y = input ; y > x; y--){
temp += "-";
}
for (let z = 1; z <= (x * 2) - 1; z++){
temp += z;
}
for (let k = input; k >= x; k--){
temp += "-";
}
temp += '\n';
}
return temp
}
console.log(nomor3(5));
The logic for each level - say 4th level - it begins with the digit of the level to the count of the digit, then one less and so on. So line 4 looks like 4444-333-22-1 and backwards (dashes added for demonstration).
So here we build each line like that, starting from the biggest so we know its length so we can center other lines with dashes. We use arrays here and reversing them because it's easier than strings. But lastly we join so we have a string.
function pyramide(level) {
var len = null;
var result = [];
while (level > 0) {
var arr = [];
for (var i = level; i > 1; i--) {
for (var repeat = 0; repeat < i; repeat++) {
arr.push(i)
}
}
var str_level = arr.join("") + "1" + arr.reverse().join("");
if (len === null) {
len = str_level.length;
}
while (str_level.length < len) {
str_level = "-" + str_level + "-";
}
result.push(str_level);
level--;
}
return result.reverse().join("\n");
}
console.log(pyramide(5))

Create staircase from symbols using javascript

I want to output the staircase from the symbols "#". It should look like this:
but all I achieve is this:
What should I do to get right output?
var n = 6;
var rows=[];
var cols=[];
for(i=n-1;i>=0;i--) {
rows=[];
for(j=0;j<n;j++) {
if(j >= i) {
rows[j] = "#";
} else {
rows[j] = "";
}
}
cols.push(rows);
cols.splice(0, cols.length - 1);
console.log(cols.join(","));
}
Think of it as a coordinate system, loop through y and x and add the needed symbols.
Remember to increase max x with current y if you want it dual sided.
function ladder(size, dualSided, empty, occupied) {
if (dualSided === void 0) { dualSided = true; }
if (empty === void 0) { empty = " "; }
if (occupied === void 0) { occupied = "▲"; }
var str = "";
for (var y = 0; y < size; y++) {
for (var x = 0; x < size + y; x++) {
if (dualSided != true && x == size) {
break;
}
if (x >= size - y - 1) {
str += occupied;
}
else {
str += empty;
}
}
str += "\n";
}
return str;
}
console.log(ladder(20, false));
Ok, try this(last 3 lines);
cols.push(rows.join(""));
cols.splice(0, cols.length - 1);
console.log(cols.join(""));
The issue is you are pushing array(row) in cols, where row array itself contains comma. If you do cols.push(rows.join("")) , all comma will be removed.
Simple solution using Array.from
Live demo check below.
function staircase(n) {
let arr = Array.from({ length: n }).fill(0);
arr.map((v,i) => {
let dummyArr = Array.from({ length: i+1 }).fill('#');
let spaceArr = Array.from({ length: arr.length - (i+1) }).fill(' ');
console.log(`${spaceArr.join('')}${dummyArr.join('')}`);
});
}
staircase(6);
try this simple solution
for (let i = 1; i <= n; i++) {
console.log("#".repeat(i).padStart(n));
}

A while loop to add the digits of a multi-digit number together? (Javascript)

I need to add the digits of a number together (e.g. 21 is 2+1) so that the number is reduced to only one digit (3). I figured out how to do that part.
However,
1) I may need to call the function more than once on the same variable (e.g. 99 is 9+9 = 18, which is still >= 10) and
2) I need to exclude the numbers 11 and 22 from this function's ambit.
Where am I going wrong below?
var x = 123;
var y = 456;
var z = 789;
var numberMagic = function (num) {
var proc = num.toString().split("");
var total = 0;
for (var i=0; i<proc.length; i++) {
total += +proc[i];
};
};
while(x > 9 && x != 11 && x != 22) {
numberMagic(x);
};
} else {
xResult = x;
};
console.log(xResult);
//repeat while loop for y and z
Here are the problems with your code
var x = 123;
var y = 456;
var z = 789;
var numberMagic = function (num) {
var proc = num.toString().split("");
var total = 0;
for (var i=0; i<proc.length; i++) {
total += +proc[i]; // indentation want awry
}; // don't need this ; - not a show stopper
// you're not returning anything!!!!
};
while(x > 9 && x != 11 && x != 22) {
numberMagic(x);
}; // ; not needed
// because x never changes, the above while loop would go on forever
} else { // this else has no if
xResult = x; // even if code was right, x remains unchanged
};
console.log(xResult);
Hope that helps in some way
Now - here's a solution that works
var x = 123;
var y = 456;
var z = 789;
var numberMagic = function (num) {
while (num > 9) {
if (num == 11 || num == 22) {
return num;
}
var proc = num.toString().split("");
num = proc.reduce(function(previousInt, thisValueString) {
return previousInt + parseInt(thisValueString);
}, 0);
}
return num;
}
console.log(numberMagic(x));
console.log(numberMagic(y));
console.log(numberMagic(z));
I'm not sure to understand what you want..
with this function you reduce any number to one single digit
while(num > 9){
if(num == 11 || num == 22) return;
var proc = num.toString();
var sum = 0;
for(var i=0; i<proc.length; i++) {
sum += parseInt(proc[i]);
}
num = sum;
}
is it what you are looking at?
I wrote an example at Jsfiddle that you can turn any given number into a single digit:
Example input: 551
array of [5, 5, 1] - add last 2 digits
array of [5, 6] - add last 2 digits
array of [1, 1] - add last 2 digits
array of [2] - output
Here is the actual code:
var number = 1768;
var newNumber = convertToOneDigit(number);
console.log("New Number: " + newNumber);
function convertToOneDigit(number) {
var stringNumber = number.toString();
var stringNumberArray = stringNumber.split("");
var stringNumberLength = stringNumberArray.length;
var tmp;
var tmp2;
var tmp3;
console.log("Array: " + stringNumberArray);
console.log("Array Length: " + stringNumberLength);
while (stringNumberLength > 1) {
tmp = parseInt(stringNumberArray[stringNumberLength - 1]) + parseInt(stringNumberArray[stringNumberLength - 2]);
stringNumberArray.pop();
stringNumberArray.pop();
tmp2 = tmp.toString();
if (tmp2.length > 1) {
tmp3 = tmp2.split("");
for (var i = 0; i < tmp3.length; i++) {
stringNumberArray.push(tmp3[i]);
}
} else {
stringNumberArray.push(tmp2);
}
stringNumberLength = stringNumberArray.length;
console.log("Array: " + stringNumberArray);
console.log("Array Length: " + stringNumberLength);
}
return stringNumberArray[0];
}
function addDigits(n) {
let str = n.toString().split('');
let len = str.length;
let add,
acc = 0;
for (i=0; i<=len-1; i++) {
acc += Number(str[i]);
}
return acc;
}
console.log( addDigits(123456789) ); //Output: 45
Just make it a While loop, remember a While loops it's just the same as a For loop, only you add the counter variable at the end of the code, the same way you can do with a Do{code}while(condition) Only need to add a counter variable at the end and its gonna be the same. Only that the variable its global to the loop, I mean comes from the outside.
Ej.
let i = 0; //it's global to the loop, ( wider scope )
while (i<=x) {
//Code line;
//Code line;
//Code line;
//Code line;
i++
}
Now this is working with an outside variable and it's NOT recommended.. unless that var its local to a Function.
Please look at the this solution also
var x = 123;
var y = 456;
var z = 789;
var numberMagic = function (num) {
var total = 0;
while (num != 0) {
total += num % 10;
num = parseInt(num / 10);
}
console.log(total);
if (total > 9)
numberMagic(total);
else
return total;
}
//Call first time function
numberMagic(z);

Create range of letters and numbers

I'm creating a form where users can input a range. They are allowed to input letters and numbers. Some sample input:
From: AA01
To: AZ02
Which should result in:
AA01
AA02
AB01
AB02
And so on, till AZ02
And:
From: BC01
To: DE01
Should result in:
BC01
BD01
BE01
CC01
CD01
CE01
Etc
I managed to get it working for the input A01 to D10 (for example)
jsFiddle
However, i can't get it to work with multiple letters.
JS code:
var $from = $('input[name="from"]');
var $to = $('input[name="to"]');
var $quantity = $('input[name="quantity"]');
var $rangeList = $('.rangeList');
var $leadingzeros = $('input[name="leadingzeros"]');
$from.on('keyup blur', function () {
$(this).val($(this).val().replace(/[^a-zA-Z0-9]/g, ''));
updateQuantity();
});
$to.on('keyup blur', function () {
$(this).val($(this).val().replace(/[^a-zA-Z0-9]/g, ''));
updateQuantity();
});
$leadingzeros.on('click', function () {
updateQuantity();
});
function updateQuantity() {
var x = parseInt($from.val().match(/\d+/));
var y = parseInt($to.val().match(/\d+/));
var xl = $from.val().match(/[a-zA-Z]+/);
var yl = $to.val().match(/[a-zA-Z]+/);
var result = new Array();
if (xl != null && yl != null && xl[0].length > 0 && yl[0].length > 0) {
xl = xl[0].toUpperCase();
yl = yl[0].toUpperCase();
$rangeList.html('');
var a = yl.charCodeAt(0) - xl.charCodeAt(0);
for (var i = 0; i <= a; i++) {
if (!isNaN(x) && !isNaN(y)) {
if (x <= y) {
var z = (y - x) + 1;
$quantity.val(z * (a + 1));
$rangeList.html('');
for (var b = z; b > 0; b--) {
var c = ((y - b) + 1);
if ($leadingzeros.prop('checked')) {
c = leadingZeroes(c, y.toString().length);
}
result.push(String.fromCharCode(65 + i) + c);
}
} else {
$rangeList.html('');
$quantity.val(0);
}
} else {
$rangeList.html('');
$quantity.val(0);
}
}
} else if (!isNaN(x) && !isNaN(y)) {
if (x < y) {
var z = (y - x) + 1;
$quantity.val(z);
$rangeList.html('');
for (var i = z; i > 0; i--) {
var c = (y - i) + 1;
if ($leadingzeros.prop('checked')) {
c = leadingZeroes(c, y.toString().length);
}
result.push(c);
}
} else {
$rangeList.html('');
$quantity.val(0);
}
} else {
$rangeList.html('');
$quantity.val(0);
}
$rangeList.html('');
for (var i = 0; i < result.length; i++) {
$rangeList.append(result[i] + '<br />');
}
}
function leadingZeroes(number, size) {
number = number.toString();
while (number.length < size) number = "0" + number;
return number;
}
This is perfect for a recursive algorithm:
function createRange(from, to) {
if (from.length === 0) {
return [ "" ];
}
var result = [];
var innerRange = createRange(from.substring(1), to.substring(1));
for (var i = from.charCodeAt(0); i <= to.charCodeAt(0); i++) {
for (var j = 0; j < innerRange.length; j++) {
result.push(String.fromCharCode(i) + innerRange[j]);
}
}
return result;
}
Called as follows:
createRange('BC01', 'DE02'); // Generates an array containing all values expected
EDIT: Amended function below to match new test case (much more messy, however, involving lots of type coercion between strings and integers).
function prefixZeroes(value, digits) {
var result = '';
value = value.toString();
for (var i = 0; i < digits - value.length; i++) {
result += '0';
}
return result + value;
}
function createRange(from, to) {
if (from.length === 0) {
return [ "" ];
}
var result = [];
if (from.charCodeAt(0) < 65) {
fromInt = parseInt(from);
toInt = parseInt(to);
length = toInt.toString().length;
var innerRange = createRange(from.substring(length), to.substring(length));
for (var i = fromInt; i <= toInt; i++) {
for (var j = 0; j < innerRange.length; j++) {
result.push(prefixZeroes(i, length) + innerRange[j]);
}
}
} else {
var innerRange = createRange(from.substring(1), to.substring(1));
for (var i = from.charCodeAt(0); i <= to.charCodeAt(0); i++) {
for (var j = 0; j < innerRange.length; j++) {
result.push(String.fromCharCode(i) + innerRange[j]);
}
}
}
return result;
}
Please note that because of your strict logic in how the value increments this method requires exactly 4 characters (2 letters followed by 2 numbers) to work. Also, this might not be as efficient/tidy as it can be but it took some tinkering to meet your logic requirements.
function generate(start, end) {
var results = [];
//break out the start/end letters/numbers so that we can increment them seperately
var startLetters = start[0] + start[1];
var endLetters = end[0] + end[1];
var startNumber = Number(start[2] + start[3]);
var endNumber = Number(end[2] + end[3]);
//store the start letter/number so we no which value to reset the counter to when a maximum boundry in reached
var resetLetter = startLetters[1];
var resetNumber = startNumber;
//add first result as we will always have at least one
results.push(startLetters + (startNumber < 10 ? "0" + startNumber : "" + startNumber));
//maximum while loops for saefty, increase if needed
var whileSafety = 10000;
while (true) {
//safety check to ensure while loop doesn't go infinite
whileSafety--;
if (whileSafety == 0) break;
//check if we have reached the maximum value, if so stop the loop (break)
if (startNumber == endNumber && startLetters == endLetters) break;
//check if we have reached the maximum number. If so, and the letters limit is not reached
//then reset the number and increment the letters by 1
if (startNumber == endNumber && startLetters != endLetters) {
//reset the number counter
startNumber = resetNumber;
//if the second letter is at the limit then reset it and increment the first letter,
//otherwise increment the second letter and continue
if (startLetters[1] == endLetters[1]) {
startLetters = '' + String.fromCharCode(startLetters.charCodeAt(0) + 1) + resetLetter;
} else {
startLetters = startLetters[0] + String.fromCharCode(startLetters.charCodeAt(1) + 1);
}
} else {
//number limit not reached so just increment the number counter
startNumber++;
}
//add the next sequential value to the array
results.push(startLetters + (startNumber < 10 ? "0" + startNumber : "" + startNumber));
}
return results;
}
var results = generate("BC01", "DE01");
console.log(results);
Here is a working example, which uses your second test case
Using #Phylogenesis' code, i managed to achieve my goal.
jsFiddle demo
function updateQuantity() {
var x = parseInt($from.val().match(/\d+/));
var y = parseInt($to.val().match(/\d+/));
var xl = $from.val().match(/[a-zA-Z]+/);
var yl = $to.val().match(/[a-zA-Z]+/);
var result = new Array();
var r = createRange(xl[0], yl[0]);
var z = (y - x) + 1;
if (x <= y) {
for (var j = 0; j < r.length; j++) {
var letters = r[j];
for (var i = z; i > 0; i--) {
var c = (y - i) + 1;
if ($leadingzeros.prop('checked')) {
c = leadingZeroes(c, y.toString().length);
}
if (i == z) {
r[j] = letters + c + '<br />';
} else {
j++;
r.splice(j, 0, letters + c + '<br />');
}
}
}
} else {
for (var i = 0; i < r.length; i++) {
r[i] += '<br />';
}
}
$quantity.val(r.length);
$rangeList.html('');
for (var i = 0; i < r.length; i++) {
$rangeList.append(r[i]);
}
}
This works for unlimited letters and numbers, as long as the letters are first.
Thanks for your help!

Javascript Loto Game

How can I check for matching numbers in this script, stuck here, I need to compare the array of user numbers with the array of lotto numbers and display how many numbers they got correct if any along with their prize value.
function numbers() {
var numbercount = 6;
var maxnumbers = 40;
var ok = 1;
r = new Array(numbercount);
for (var i = 1; i <= numbercount; i++) {
r[i] = Math.round(Math.random() * (maxnumbers - 1)) + 1;
}
for (var i = numbercount; i >= 1; i--) {
for (var j = numbercount; j >= 1; j--) {
if ((i != j) && (r[i] == r[j])) ok = 0;
}
}
if (ok) {
var output = "";
for (var k = 1; k <= numbercount; k++) {
output += r[k] + ", ";
}
document.lotto.results.value = output;
} else numbers();
}
function userNumbers() {
var usersNumbers = new Array(5);
for (var count = 0; count <= 5; count++) {
usersNumbers[count] = window.prompt("Enter your number " + (count + 1) + ": ");
}
document.lotto.usersNumbers.value = usersNumbers;
}
Here is a lotto numbers generator and a scoring system. I'm going to leave it to you to validate the user input.
function lottoGen(){
var lottoNumbers = [];
for(var k = 0; k<6; k++){
var num = Math.floor(Math.random()*41);
if(lottoNumbers.indexOf(num) != -1){
lottoNumbers.push(num);
}
}
return lottoNumbers;
}
function scoreIt(){
var usersNumbers = document.getElementsByName('usersNumbers').item(0);
usersNumbers = String(usersNumbers)
usersNumbers = usersNumbers.split(' ');
var matches = 0;
for(var i = 0; i<6; i++){
if(lottoNumbers.indexOf(usersNumbers[i]) != -1){matches++;}
}
return matches;
}
Hi I'm new to this and trying to learn off my own back so obviously I'm no expert but the code above makes a lot of sense to me, apart from the fact I can't get it to work.. I tried to console.log where it says RETURN so I could see the numbers but it just shows an empty array still. I assumed this was to do with it being outside the loop..
I've tried various ways but the best I get is an array that loops the same number or an array with 6 numbers but some of which are repeated..
function lottoGen(){
var lottoNumbers = [];
for(var k = 0; k<6; k++){
var num = Math.floor(Math.random()*41);
if(lottoNumbers.indexOf(num) != -1){
lottoNumbers.push(num);
}
}
return lottoNumbers;
}
Lotto JS: CODEPEN DEMO >> HERE <<
(function(){
var btn = document.querySelector("button");
var output = document.querySelector("#result");
function getRandom(min, max){
return Math.round(Math.random() * (max - min) + min);
}
function showRandomNUmbers(){
var numbers = [],
random;
for(var i = 0; i < 6; i++){
random = getRandom(1, 49);
while(numbers.indexOf(random) !== -1){
console.log("upps (" + random + ") it is in already.");
random = getRandom(1, 49);
console.log("replaced with: (" + random + ").");
}
numbers.push(random);
}
output.value = numbers.join(", ");
}
btn.onclick = showRandomNUmbers;
})();

Categories

Resources