I can't wrap my head around a piece of code using loops and functions in javascript.
I have a function which generates random numbers (between a min and max), see below:
const getRandomNumber = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Below a simple Function which returns true if 2 random numbers add up to 10, else it returns false:
const Function1 = (n1, n2) => (n1 + n2 === 10) ? true : false
Below i will use Function1 to return n1 and n2:
const Function1Check= () => {
const n1 = getRandomNumber(-10, 10);
const n2 = getRandomNumber(-10, 10);
if(Function1(n1, n2)) {
return [n1, n2]
} else {
return {false}
}
}
const LoopFunction = () => {
while(Function1Check === false) {
Function1Check();
if(Function1Check) {break;}
}
}
My while loop does not work correctly, what am i missing?
Hope you guys can help me out and point me in the right direction using vanilla javascript.
Thanks in advance.
Greetings.
You can use a do.. while loop and quit after a maximum number of attempts to avoid an infinite loop.
The loop will also terminate once the target length of the array is reached:
const getRandomNumber = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min; // max & min both included
}
const Function1 = (n1, n2) => (n1 + n2 === 10) ? true : false
const Function1Check = () => {
const n1 = getRandomNumber(-10, 10);
const n2 = getRandomNumber(-10, 10);
if(Function1(n1, n2)) {
return [n1, n2]
} else {
return false;
}
}
let rightNumbers = [];
let attempts = 0;
let maxAttempts = 1000;
let target = 5;
do {
let numbers = Function1Check();
if (numbers) {
rightNumbers.push(numbers);
}
} while (rightNumbers.length < target && (attempts++) < maxAttempts)
console.log(`Found ${target} number(s) after ${attempts} attempts`);
console.log(`Numbers:`, rightNumbers)
If your program freezes that's a clear sign that your while loop doesn't stop.
I'd approach it the following way:
const AMOUNT_OF_RESULTS = 5;
const results = [];
// This would be the correct predicate to stop your while loop.
// You want to stop looping once you have 5 correct results.
while (results.length < AMOUNT_OF_RESULTS ) {
const result = checkRightNumbers();
// If result is not false(an array in your case)
if(!result) {
// Then add the result to the array of results:
results.push(result);
}
}
The loop will continue generating results until it filled the quota(AMOUNT_OF_RESULTS).
A method which achieves what you are trying to do looks something like this:
const getSolutionSet = () => {
let answers = [];
while(answers.length < 5){
let check = checkRightNumbers();
if(check){
answers.push(check);
}
}
return answers;
}
You could make it a bit more advanced, by passing the amount of results as a parameter
const getSolutionSet = (numResults) => {
let answers = [];
while(answers.length < numResults){
let check = checkRightNumbers();
if(check){
answers.push(check);
}
}
return answers;
}
You should keep in mind, that the probability is pretty low to find an exact match, so adding a max number of tries would also be a good idea
Related
I am running npm test for my code and I am failing the third test out of six test.
I've tried to sort it with the following :
sumAll.sort(function(min,max)) {
return max - min;
}
But it's not working. I tried to add conditionals in the code by using 'if (min > max )... else if ( min < max )' but it still don't work too. I tried adding '0' on the reducer variable 'accumulator + currentValue, 0' but still it's not working. Is there any way how can I sort the sumAll function so it's still working even if it use a higher 'min' arguments than the 'max' argument ? Please help.
const sumAll = function( min, max ) {
let fullArr = [];
let sum = 0;
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// let highestToLowest =
for ( let i = min; i <= max; i++) {
fullArr.push(i);
}
// sumAll.sort(function(min,max)) {
// return max - min;
// }
// // let lowestToHighest = fullArr.sort((a, b) => a - b);
// let highestToLowest = fullArr.sort((min, max) => max-min);
sum = fullArr.reduce(reducer);
return sum;
}
sumAll(1,4);
sumAll(123, 1); <---------- I failed on this function call saying it 'Reduce
of empty array with no initial value....
---------------------------- Jest code --------------------------
const sumAll = require('./sumAll')
describe('sumAll', () => {
test('sums numbers within the range', () => {
expect(sumAll(1, 4)).toEqual(10);
});
test('works with large numbers', () => {
expect(sumAll(1, 4000)).toEqual(8002000);
});
test('works with larger number first', () => {
expect(sumAll(123, 1)).toEqual(7626);
});
test.skip('returns ERROR with negative numbers', () => {
expect(sumAll(-10, 4)).toEqual('ERROR');
});
test.skip('returns ERROR with non-number parameters', () => {
expect(sumAll(10, "90")).toEqual('ERROR');
});
test.skip('returns ERROR with non-number parameters', () => {
expect(sumAll(10, [90, 1])).toEqual('ERROR');
});
});
The reducer to sum array value is :
arr.reduce((ac, cv) => ac + cv, 0);
Add a initial value should prevent error : empty array with no initial value
This code works for me :
const sumAll = function( min, max ) {
let fullArr = [];
let sum = 0;
for ( let i = min; i <= max; i++) {
fullArr.push(i);
}
sum = fullArr.reduce((ac, cv) => ac + cv, 0);
return sum;
}
console.log(sumAll(1,4));
console.log(sumAll(123,1));
// Output 10
// Output 0 (because min < max)
If you want sumAll(123, 1) to print 7626 you have to switch both min and max when min > max
For exemple use this for loop :
for ( let i = (min <= max ? min : max); i <= (max >= min ? max : min); i++) { }
or as suggested by #adiga :
if( min > max) [min, max] = [max, min];
I'm trying to solve a question to be able to add strings that include floating point numbers. For example "110.75" + "9" = "119.75".
I have the code below that I have been wrestling with for about an hour now and could appreciate if anybody could point me in the right direction as to where I might be wrong. I am only returning an empty string "" for every test case I write for myself.
var addStrings = function(num1, num2) {
const zero = 0;
let s1 = num1.split(".");
let s2 = num2.split(".");
result = "";
let sd1 = s1.length > 1 ? s1[1] : zero;
let sd2 = s2.length > 1 ? s2[1] : zero;
while(sd1.length !== sd2.length) {
if(sd1.length < sd2.length) {
sd1 += zero
} else {
sd2 += zero;
}
}
let carry = addStringHelper(sd1, sd2, result, 0);
result.concat(".");
addStringHelper(s1[0], s2[0], result, carry);
return result.split("").reverse().join("");
};
function addStringHelper(str1, str2, result, carry) {
let i = str1.length - 1;
let j = str2.length - 1;
while(i >= 0 || j >= 0) {
let sum = carry
if(j >= 0) {
sum += str1.charAt(j--) - '0';
}
if(i >= 0 ) {
sum += str2.charAt(i--) - '0';
}
carry = sum / 10;
result.concat(sum % 10);
}
return carry
}
Convert the strings into Number, add them and then convert them back to String.
const addStrings = (num1, num2) => String(Number(num1) + Number(num2))
console.log(addStrings("110.67", "9"))
Also, try to handle floating point rounding in some way. You can try using toFixed (this will fix the result to two decimal places).
const addStrings = (num1, num2) => String((Number(num1) + Number(num2)).toFixed(2))
console.log(addStrings("0.2", "0.1"))
I need some help with a task which is about creating a function that only accepts integer numbers to then multiply each other until getting only one digit. The answer would be the times:
Example: function(39) - answer: 3
Because 3 * 9 = 27, 2 * 7 = 14, 1 * 4 = 4 and 4 has only one digit
Example2: function(999) - answer: 4
Because 9 * 9 * 9 = 729, 7 * 2 * 9 = 126, 1 * 2 * 6 = 12, and finally 1 * 2 = 2
Example3: function(4) - answer: 0
Because it has one digit already
So trying to figure out how to solve this after many failures, I ended up coding this:
function persistence(num) {
let div = parseInt(num.toString().split(""));
let t = 0;
if(Number.isInteger(num) == true){
if(div.length > 1){
for(let i=0; i<div.length; i++){
div = div.reduce((acc,number) => acc * number);
t += 1;
div = parseInt(div.toString().split(""))
if(div.length == 1){
return t } else {continue}
} return t
} else { return t }
} else { return false }
}
console.log(persistence(39),3);
console.log(persistence(4),0);
console.log(persistence(25),2);
console.log(persistence(999),4);
/*
output: 0 3
0 0
0 2
0 4
*/
It seems I could solve it, but the problem is I don't know why those 0s show up. Besides I'd like to receive some feedback and if it's possible to improve those codes or show another way to solve it.
Thanks for taking your time to read this.
///EDIT///
Thank you all for helping and teaching me new things, I could solve this problem with the following code:
function persistence(num){
let t = 0;
let div;
if(Number.isInteger(num) == true){
while(num >= 10){
div = (num + "").split("");
num = div.reduce((acc,val) => acc * val);
t+=1;
} return t
}
}
console.log(persistence(39));
console.log(persistence(4));
console.log(persistence(25));
console.log(persistence(999));
/*output: 3
0
2
4
*/
You've got a few issues here:
let div = parseInt(num.toString().split("")); You're casting an array to a number, assuming you're trying to extract the individual numbers into an array, you were close but no need for the parseInt.
function persistence(input, count = 0) {
var output = input;
while (output >= 10) {
var numbers = (output + '').split('');
output = numbers.reduce((acc, next) {
return Number(next) * acc;
}, 1);
count += 1;
}
return count;
};
For something that needs to continually check, you're better off using a recurssive function to check the conditions again and again, this way you won't need any sub loops.
Few es6 features you can utilise here to achieve the same result! Might be a little too far down the road for you to jump into es6 now but here's an example anyways using recursion!
function recursive(input, count = 0) {
// convert the number into an array for each number
const numbers = `${input}`.split('').map(n => Number(n));
// calculate the total of the values
const total = numbers.reduce((acc, next) => next * acc, 1);
// if there's more than 1 number left, total them up and send them back through
return numbers.length > 1 ? recursive(total, count += 1) : count;
};
console.log(recursive(39),3);
console.log(recursive(4),0);
console.log(recursive(25),2);
console.log(recursive(999),4);
function persistance (num) {
if (typeof num != 'number') throw 'isnt a number'
let persist = 0
while(num >= 10) {
let size = '' + num
size = size.length
// Get all number of num
const array = new Array(size).fill(0).map((x, i) => {
const a = num / Math.pow(10, i)
const b = parseInt(a, 10)
return b % 10
})
console.log('here', array)
// actualiser num
num = array.reduce((acc, current) => acc * current, 1)
persist++
}
return persist
}
console.log(persistance(39))
console.log(persistance(999))
console.log() can take many argument...
So for example, console.log("A", "B") will output "A" "B".
So all those zeros are the output of your persistence function... And the other number is just the number you provided as second argument.
So I guess you still have to "persist"... Because your function always returns 0.
A hint: You are making this comparison: div.length > 1...
But div is NOT an array... It is a number, stringified, splitted... And finally parsed as integer.
;) Good luck.
Side note, the calculation you are attempting is known as the Kaprekar's routine. So while learning JS with it... That history panel of the recreational mathematic wil not hurt you... And may be a good line in a job interview. ;)
My best hint
Use the console log within the function to help you degug it. Here is your unchanged code with just a couple of those.
function persistence(num) {
let div = parseInt(num.toString().split(""));
let t = 0;
console.log("div.length", div.length)
if (Number.isInteger(num) == true) {
if (div.length > 1) {
for (let i = 0; i < div.length; i++) {
div = div.reduce((acc, number) => acc * number);
t += 1;
div = parseInt(div.toString().split(""));
if (div.length == 1) {
console.log("return #1")
return t;
} else {
continue;
}
}
console.log("return #2")
return t;
} else {
console.log("return #3")
return t;
}
} else {
console.log("return #4")
return false;
}
}
console.log(persistence(39), 3);
console.log(persistence(4), 0);
console.log(persistence(25), 2);
console.log(persistence(999), 4);
I want to create a method that takes a list of numbers and can reduce the array by a supplied variance.
Variance Explained:
The variance should match a value below and above. So for example, the variance of 100 equated against the value: 5460 should match any value between 5410 - 5510. (50 below the equated value and 50 above)
For instance if I have the array:
[ 1576420754, 1576420756, 1576593554, 1581172759, 1581172764 ]
I want to created a method filterSimilarValues(array, variance = 100)
Which would give me the following output:
[ 1576420756, 1576593554, 1581172764 ]
I have tried a couple things, like
const filterSimalarValues = (array, variance = 100) => {
let filteredArray = [];
for (let i = 0; i < array.length; i++) {
const number = array[i];
if (number >= number - (variance / 2) && number <= number + (variance / 2)) {
return;
}
filteredArray.push(number);
}
return filteredArray;
};
Use Array.filter() to retain only numbers that the absolute difference (Math.abs()) between the them and the next number is greater or equal variance / 2. The last item (i === array.length - 1) is included by default.
const filterSimalarValues = (array, variance = 100) =>
array.filter((n, i) =>
i === array.length - 1 ||
Math.abs(n - array[i + 1]) >= variance / 2
)
const data = [1576420754, 1576420756, 1576593554, 1581172759, 1581172764]
const result = filterSimalarValues(data)
console.log(result)
I would try something like:
const filterSimalarValues = (array, variance = 100) =>
array.reduce((acc, curr) => {
const variant = acc.find(
item => curr > item - variance / 2 && curr < item + variance / 2,
);
if (!variant) {
acc.push(curr);
} else {
acc[acc.indexOf(variant)] = curr;
}
return acc;
}, []);
Also, in my opinion you should be more specific with your question, there are a lot of possible (edge) cases not covered.
As per the explanation provided and my understanding of variance, you want to limit the numbers between the variance range. I am assuming you have a minimum of 2 elements but you can add checks for that case.
const filterSimalarValues = (array, variance = 100) => {
const filteredArray = [];
filteredArray.push(array[0]);//bench mark to check
for (let i = 1; i < array.length; i++) {
const number_lower_bound = array[i] - variance/2;
const number_upper_bound = array[i] + variance/2;
var bound_exist = false;
for(var bound = number_lower_bound;bound<=number_upper_bound;bound++){
if (filteredArray.includes(bound)) {
bound_exist = true;
break;
}
}
if(!bound_exist){
filteredArray.push(array[i])
}
}
}
return filteredArray;
};
This is what I have come up with, it works, but there might be a better solution so I am not accepting my own answer.
const filterSimilarValues = (array, variance = 100) => {
let filteredArray = [];
array.forEach(number => {
const start = number - (variance / 2);
const end = number + (variance / 2);
const range = Array(end - start + 1).fill().map((_, idx) => start + idx);
const found = range.some(r => filteredArray.includes(r))
if (!found) {
filteredArray.push(number);
}
});
return filteredArray;
};
I am trying to get a different value from the previous value of math.random, so when the numbers are written to the document, if they are the same then math.random will generate another number that is not the same. It may need to keep generating until the value is different.
function rands() {
return Math.floor(Math.random() * 20) + 1;
}
var rand1 = rands();
var rand2 = rands();
var rand3 = rands();
var rand4 = rands();
var rand = [];
function myFunction() {
document.getElementById("random1").value = rand1;
document.getElementById("random2").value = rand2;
document.getElementById("random3").value = rand3;
document.getElementById("random4").value = rand4;
if(rand1 == rand2 || rand1==rand3 || rand1==rand4 || rand2 == rand3 || rand2 == rand4 || rand3==rand4){
console.log("Duplicate");
}
}
myFunction()
You could rewrite your rands function to look for values which have already been used:
function rands(used) {
let r;
do {
r = Math.floor(Math.random() * 20) + 1;
} while (used.indexOf(r) >= 0);
return r;
}
var rand = [];
for (let i = 0; i < 4; i++) rand[i] = rands(rand);
If you want to guarantee uniqueness you can splice random indexes from an array. This will save the effort of repeatedly calling the function when you have clashes:
function rand_maker(length) {
let arr = Array.from({length: length}, (_, i) => i+1)
return () => {
let index = Math.floor(Math.random() * arr.length)
return arr.splice(index, 1)[0];
}
}
let rands = rand_maker(20)
console.log(rands())
console.log(rands())
console.log(rands())
console.log(rands())
Once you can no longer make random numbers in the range, it will returned undefined.