I'm having a hard time to crack this one out, would appreciate a hand with this script.
Trying to do a countdown script where I have to display the new number counting from previous.
let oldN = 0;
let newN = 0;
let arr = [];
function runner() {
arr = [];
newN = document.getElementById('newVar').value;
console.log("stored: " + oldN + " new: " + newN);
if (oldN > newN) {
for (let i = oldN; i >= newN; i--) {
arr.push(i);
}
} else if (oldN < newN) {
for (let e = oldN; e <= newN; e++) {
arr.push(e);
}
}
console.log("array: " + arr.length);
oldN = newN;
for (let u = 0; u < arr.length; u++) {
(function(index) {
setTimeout(() => {
document.getElementsByTagName('span')[0].innerText = arr[index];
}, 100 * u);
})(u);
}
}
<div class="board">
<span><!----></span>
</div>
<br/>
<input type="text" id="newVar" />
<button onclick="runner()">Start</button>
It seems to work but if I go from 13 to 7 it won't populate the array thus not running the countdown, the same issue happens when going from 7 to 13.
Any idea?
Kind Regards
You forgot to convert the input value (a string) to a number. They are compared alphabetically not numerically then, and "13" < "7" so your loop doesn't work. Use
newN = parseInt(document.getElementById('newVar').value, 10);
Related
Trying to solve this HackerRank challenge:
Lilah has a string, s, of lowercase English letters that she repeated infinitely many times.
Given an integer, n, find and print the number of letter a's in the first letters of Lilah's infinite string.
For example, if the string s = abcac and n = 10, the substring we consider is abcacabcac, the first 10 characters of her infinite string. There are 4 occurrences of "a" in the substring.
I wrote:
function repeatedString(s, n) {
s = s.repeat(n);
s = s.slice(0, n);
let array = Array.from(s);
let count = 0;
for (let i = 0; i < array.length; i++) {
let char = array[i];
if (char.match(/[a]/gi)) {
count++;
}
}
return count;
}
console.log(repeatedString("abcac", 10));
But HackerRank does not like s = s.repeat(n);, apparently:
I'm not sure how else to generate a string of an appropriate length to slice from. s = s.repeat(Infinity) does not work, and s is not already repeated an infinite number of times when it's passed in as a parameter.
I.e. console.logging(s), initially, logs
abcac
In this case.
I also tried:
function repeatedString(s, n) {
let j = n;
let newString = "";
while (n > 0) {
newString += s;
n--;
}
newString = newString.slice(0, j);
let count = 0;
let array = Array.from(newString);
for (let i = 0; i < array.length; i++) {
let char = array[i];
if (char.match(/[a]/gi)) {
count++;
}
}
return count;
}
console.log(repeatedString("abcac", 10));
But this caused a timeout error.
Any other ideas for how to create a string of valid length to slice from?
EDIT:
Constraints:
1 <= |s| <= 100
1 <= n <= 10^12
For 25% of the test cases, n <= 10^6
actually repeating the string n times is a tremendous waste of memory and runtime.
just compute how often the entire string would be repeated times how many as the string has plus the number of as in the part of s.slice(0, n%s.length)
And your runtime goes down to s.length instead of n
function repeatedString(s, n) {
var r = n % s.length,
m = (n - r) / s.length,
count = 0;
for (var i = 0; i < s.length; ++i) {
if (s[i] === "a") {
count += m + (i < r);
}
}
return count;
}
console.log(repeatedString("abcac", 1234567890));
function repeatedString(s, n) {
var r = n % s.length,
m = (n - r) / s.length,
count = 0;
for (var i = 0; i < s.length; ++i) {
if (s[i] === "a") {
count += m + (i < r);
}
}
return count;
}
console.log(repeatedString("abcac", 1234567890));
I tested this and knows it works. Essentially, I'm not creating a new string, I just find out how many times I have to multiply the original string in order to be able to truncate it. Then I multiply that number by how many a's there were in the original string.
function repeatedString(s, n) {
var charLength = s.length;
var repeat = Math.floor(n/charLength);
var remainder = n%(charLength);
var strCut = s.slice(0, remainder);
let count = 0;
let arrayX = Array.from(s);
for (let i = 0; i < arrayX.length; i++) {
let char = arrayX[i];
if (char.match(/[a]/gi)) {
count++;
}
}
count = count * repeat;
let arrayY = Array.from(strCut);
for (let i = 0; i < arrayY.length; i++) {
let char = arrayY[i];
if (char.match(/[a]/gi)) {
count++;
}
}
return count;
}
console.log(repeatedString("abcac", 10));
I tried a small solution with .repeat but as Thomas said, it's expensive and was taking ages to run tests.
function repeatedString(s, n) {
const allAs = s.match(/a/g);
if (!allAs) {
return 0;
}
if (s === 'a') {
return n;
}
const reps = s.repeat(Math.ceil(n/s.length)).slice(0, n).match(/a/g)
if (!reps) return 0;
return reps.length;
};
console.log(repeatedString('abc', 10));
console.log(repeatedString('abcde', 10));
But I followed Thomas idea and came up with a simpler solution
function repeatedString(s, n) {
const allAs = s.match(/a/g);
if (!allAs) {
return 0;
}
if (s === 'a') {
return n;
}
const rem = n % s.length;
const reps = (n-rem)/s.length;
let count = reps * allAs.length;
if (rem) {
const rest = s.slice(0, rem).match(/a/g);
if (rest) count = count + rest.length
}
return count;
}
console.log(repeatedString('a', 100000));
console.log(repeatedString('abcde', 10000000000));
You could use while loop to repeat original string until length is matched and then match to count the numbers of a.
function repeatedString(s, n) {
let i = 0, l = s.length;
while (s.length < n) s += s[i++ % l]
return s.match(/a/g).length;
}
console.log(repeatedString("abcac", 10));
I did this code and it worked well.
function repeatedString(s, n) {
let modulus = n % s.length;
let repetition = (n - modulus) / s.length;
let remainCounts = s.slice(0, modulus).split("").filter((item) => item == "a").length
return (s.split("").filter((item) => item == "a").length * repetition) + remainCounts
}
enter image description here
I have an issue with a recursive algorithm, that solves the problem of finding the happy numbers.
Here is the code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
//return false;
}
}
}
}
CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Algorithm is working ALMOST fine. I've tested it out by calling function with different numbers, and console was displaying correct results. The problem is that I almost can't get any value from the function. There are only few cases in which I can get any value: If the number is build out of ,,0", and ,,1", for example 1000.
Because of that, I figured out, that I have problem with returning any value when the function is calling itself again.
Now I ended up with 2 results:
Returning the
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
which is giving an infinity looped number. For example when the number is happy, the function is printing in the console number one again and again...
Returning the
//return true
or
//return false
which gives me an undefined value
I'm a little bit in check by this problem, and I'm begging you guys for help.
I would take a step back and reexamine your problem with recursion in mind. The first thing you should think about with recursion is your edge cases — when can you just return a value without recursing. For happy numbers, that's the easy case where the sum of squares === 1 and the harder case where there's a cycle. So test for those and return appropriately. Only after that do you need to recurse. It can then be pretty simple:
function sumSq(num) {
/* simple helper for sums of squares */
return num.toString().split('').reduce((a, c) => c * c + a, 0)
}
function isHappy(n, seen = []) {
/* seen array keeps track of previous values so we can detect cycle */
let ss = sumSq(n)
// two edge cases -- just return
if (ss === 1) return true
if (seen.includes(ss)) return false
// not an edge case, save the value to seen, and recurse.
seen.push(ss)
return isHappy(ss, seen)
}
console.log(isHappy(23))
console.log(isHappy(22))
console.log(isHappy(7839))
Here's a simplified approach to the problem
const digits = x =>
x < 10
? [ x ]
: [ ...digits (x / 10 >> 0), x % 10 ]
const sumSquares = xs =>
xs.reduce ((acc, x) => acc + x * x, 0)
const isHappy = (x, seen = new Set) =>
x === 1
? true
: seen.has (x)
? false
: isHappy ( sumSquares (digits (x))
, seen.add (x)
)
for (let n = 1; n < 100; n = n + 1)
if (isHappy (n))
console.log ("happy", n)
// happy 1
// happy 7
// happy 10
// ...
// happy 97
The program above could be improved by using a technique called memoization
Your code is almost correct. You just forgot to return the result of the recursive call:
function TestingFunction(number){
sumNumberContainer = new Array(0);
if (CheckIfNumberIsHappy(number))
console.log(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
for (let i=0; i<100; ++i)
TestingFunction(i.toString()); // 1 7 10 13 ... 91 94 97
I've got the solution, which was given to me in the comments, by the user: Mark_M.
I just had to use my previous
return true / return false
also I had to return the recursive statement in the function, and return the value of the CheckIfTheNumberIsHappy function, which was called in TestingFunction.
The working code:
function TestingFunction(number){
sumNumberContainer = new Array(0);
return CheckIfNumberIsHappy(number);
}
function CheckIfNumberIsHappy(number){
var sumOfTheNumbers = 0;
for (var i = 0; i < number.length; i++) {
sumOfTheNumbers += Math.pow(parseInt(number[i]), 2);
}
console.log(sumOfTheNumbers);
if(sumOfTheNumbers == 1){
return true;
} else {
sumNumberContainer.push(sumOfTheNumbers);
if(sumNumberContainer.length > 1){
for (var i = 0; i < sumNumberContainer.length - 1; i++) {
for (var j = i + 1; j < sumNumberContainer.length; j++) {
if(sumNumberContainer[i] == sumNumberContainer[j]){
return false;
}
}
}
}
return CheckIfNumberIsHappy(sumOfTheNumbers.toString());
}
}
Thanks for the great support :)
I am trying to write a JavaScript code that will take a users input and find the mean. Then it should put the numbers above the mean in a list and the numbers below the mean. Everything is working except for the sorting of the numbers below and above the mean. Than you for your help.
function getNums()
{
var nums = new Array();
var numAmt = prompt("How many data values do you have?");
numAmt = parseInt(numAmt);
var i = 0;
for (i = 0; i<= numAmt - 1; i++)
{
nums[i]= prompt("Enter the data value number " + (i + 1));
}
var sum = 0;
for(i = 0; i < nums.length; i++)
{
sum += parseInt(nums[i]);
var avg = sum/nums.length;
}
var big = 0;
var small = 0;
for (i = 0; i < nums.length; i++)
{
if (nums[i] > avg)
big += parseInt(numbers[i]);
else
small += parseInt(numbers[i]);
document.getElementById('numbers').innerHTML = "Your data: " + nums;
document.getElementById('average').innerHTML =("The mean(average) of these numbers is: " + avg.toFixed(2) +".<br>");
document.getElementById('bigger').innerHTML = "Your data: " + big;
document.getElementById('smaller').innerHTML = "Your data: " + small;
}
}
I would personally break this into two functions, one focused on "find the mean of this array", and another on "sort this array around a pivot."
function mean(arr) {
var sum = arr.reduce(function (prev, curr) {
return prev + curr;
});
return sum / arr.length;
}
function pivotSort(arr, pivot) {
var sorted = [];
arr.forEach(function (val) {
if (val >= pivot)
sorted.push(val);
else
sorted.unshift(val);
});
}
The pivot sort is not even close to optimized, but heck, v8 is pretty quick nowadays.
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;
})();
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>':''));
});