var candidates = {
"1":"Barack Obama",
"2":"Mitt Romney",
"3":"Dennis Kucinich",
"4":"Quentin Tarantino",
"5":"Count Dracula"
};
function getRandomInt(min, max){
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Object.size = function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
function getRandomPresident(){
var num = getRandomInt(1, Object.size(candidates));
if (num!=5){
alert(num);
var key = num.toString();
var res = candidates[key];
return res;
} else {
getRandomPresident();
}
}
alert(getRandomPresident());
This code works, but sometimes after generating random value it outputs "undefined" instead of the name - http://jsbin.com/uriwal/edit#source Why?
When trying again (the else block), you don't return the new value. You should pass the return value through:
return getRandomPresident();
Currently, you're picking a new item, but as the function doesn't return it, the return value is undefined.
I'm guessing the getRandomInt() function can return 0, which your associative array does not have. Just create a tighter check in the if clause:
if (num >= 1 && num <= 5) {
// do stuff
}
EDIT:
Scratch that, you have getRandomInt(1, max). In any case, why even have a recursive function? Just do this:
var num = 0;
while ((num = getRandomInt(1, ...)) > 5) {
num = getRandomInt(1, ...);
}
// return the resource
Hope this helps
Change function to this:
function getRandomInt(min, max){
return Math.floor(Math.random() * (max - min)) + min;
}
Related
var yourself = {
fibonacci : function(n) {
return n === 0 ? 0 : n === 1 ? 1 :
this.fibonacci(n -1) + this.fibonacci (n-2)
}
};
This function is constantly setting the value of its 'fibonacci' property based on the
arguement supplied for 'n' parameter of the function.
I would like to refactor the function to reduce execution time
Using dynamic programming, Memoization that cache the already calculated result
read more about memoization here
const memoFib = function () {
let memo = {}
return function fib(n) {
if (n in memo) { return memo[n] }
else {
if (n <= 1) { memo[n] = n }
else { memo[n] = fib(n - 1) + fib(n - 2) }
return memo[n]
}
}
}
const fib = memoFib()
console.log(fib(50));
You could implement some kind of caching. This way you don't need to recalculate the same result multiple times.
var yourself = {
fibonacci : function(n, cache = new Map()) {
if(cache.has(n)) return cache.get(n);
if(n === 0) return 0;
if(n === 1) return 1;
const start = this.fibonacci(n-1, cache);
const end = this.fibonacci(n-2, cache);
cache.set(n-1, start);
cache.set(n-2, end);
return start + end;
}
};
console.log(yourself.fibonacci(40));
I found an question and would like to try if I can write a better function without using recursive function and while loop.
But I found that I have no idea how to write it better. Is there anyone who can give me some hints or inspire me.
function recursivefunction(i, val) {
if (!val) val= 0;
if (i < 2) throw new Error('wrong input');
if (i === 2) return 1 / i + val;
return recursivefunction(i - 1, val+ 1 / (i * (i -1)));
}
Write a program doing the same calculation without
recursion.
function recursivefunction(i, val) {
if (!val) val= 0;
if (i < 2) throw new Error('wrong input');
if (i === 2) return 1 / i + val;
return recursivefunction(i - 1, val+ 1 / (i * (i -1)));
}
function nonRecursiveFunction(i, val) {
if (!val) val = 0;
if (i < 2) throw new Error('wrong input');
while(i > 2) {
val = val + 1 / (i * (i -1));
i--;
}
return 1 / i + val;
}
const recursive = recursivefunction(4, 2);
const nonrecursive = nonRecursiveFunction(4, 2);
console.log(`Recusrive: ${recursive}, nonrecursive: ${nonrecursive}`);
To be honest, I'd replace the return statement with val + 0.5, because we know that i is exactly 2 and we can use a constant value instead of dividing here.
I am trying to create a function that generates a random number from a given interval, but I want to be able to generate only 3 identical consecutive numbers. For example, if a have the interval [0,4) I want:
Accepted: 1, 2, 2, 2, 1, 0
Not accepted: 1, 2, 2, 2, 2, 3, 0
I've found on multiple threads functions that generates a different number than the previous one, but I don't know how to change it to accomplish what I need. Any thoughts?
You must completely reset your counter, when you generate a different number. Not just decrease it.
function setRandomInterval(min, max, allowedRepeats) {
var last, // keeping the last random value
repeatCount = 0, // count of repeated value
getR = function () { return Math.floor(Math.random() * (max - min)) + min; };
if (min >= max) {
throw 'Selected interval [' + min + ', ' + max + ') does not work for random numbers.';
}
return function () {
var r = getR();
if (r != last) {
repeatCount = 0; //no repeat yet
} else if (repeatCount < allowedRepeats) { //new number is equal to last one, but it's still ok
repeatCount++; //just increase the number of repeats
} else { //new number is equal to last, and allowed number of repeats is reached
while (r == last) { //must create a different number
r = getR();
}
repeatCount = 0; //reset the repeatCount
}
return last = r; //save r as last number and return it
};
}
var getRandom = setRandomInterval(0, 4, 2); //call with 2 allowed repeats to allow a sequence of three equal numbers
Try this
function randomBetween(min, max, limit = 3) {
if (min > max) {
[max, min] = [min, max];
}
function getBetween(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
let last;
let count = 0;
return function generate() {
const result = getBetween(min, max);
count = (result === last) ? count + 1 : 0;
if (count > limit) {
return generate();
}
last = result;
return result;
};
}
Here's a snippet that prevent from the same number to randomize more than 3 times. If the count of the number is greater than the limit the randomNumber is called again (and so on until it won't get the same value.
You can see (when running it) that the largest sequence is 3.
const limit = 3;
let last = null,
count = 0;
function getRndInteger(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function randomNumber(min, max) {
let num = getRndInteger(min, max);
if (last !== num) {
last = num;
count = 0;
}
count++;
if (count > limit) {
num = randomNumber(min, max);
}
return num;
}
for (let i = 0; i < 20; i++)
console.log(randomNumber(0, 2));
Here is an approach that's uses a nice feature of modern JS. Generators..
Using generators you can create composable code. Instead of creating 1 function that does this one specific thing, you can compose a function than stream together multiple generators. This is great for making re-usable code.
Below I've created 3 function,.
randomValues => this just generates random number between a range.
repeatLimit => this generator just prevents x amount of repeated values
iterCount => this generator stop after count iterations
All you do then is compose all these generators together, but the bonus is that these generators can be used in other places. eg. [...repeatLimit(3, [1,1,1,1, 0,0,0,0])] would return 1,1,1,0,0,0.
function* randValues(min, max) {
const range = max - min;
while (true)
yield min + Math.trunc(Math.random() * range);
}
function* repeatLimit(limit, gen) {
let rcount = 0, rvalue;
for (let g of gen) {
if (rvalue === g) rcount += 1; else rcount = 1;
rvalue = g;
if (rcount <= limit) yield g;
}
}
function* iterCount(count, gen) {
for (let g of gen) {
yield g;
count --;
if (count <= 0) break;
}
}
const gen =
iterCount(22, repeatLimit(3, randValues(0, 2)));
for (const r of gen) {
console.log(r);
}
In my angular application, I am using a loop to find in an object the nearest value to a given number and return its key.
For example, I want the closest values to 0.5:
for (var j in nums) {
if (0.5 > nums[j]) var prev = nums[j];
else if (0.5 <= nums[j]) {
// If the current number is equal to 0.5, or immediately higher, stores that number
// and stops the for each() loop
var next = nums[j];
// Get the value
var percentage = (Math.abs(0.5 - prev) < Math.abs(next - 0.5)) ? prev : next;
// Get the key from the value
$scope.seventyfive = parseInt('0' + Object.keys(nums).filter(function(key) {return nums[key] === percentage;})[0], 10);
break;
}
}
JSLint is pointing out that I shouldn't make functions within a loop, so I am trying to avoid that with:
filterPct = function (nums, pct) {
return function () {
return nums[key] === pct;
};
}
and
for (var j in nums) {
if (0.5 > nums[j]) var prev = nums[j];
else if (0.5 <= nums[j]) {
// If the current number is equal to 0.5, or immediately higher, stores that number
// and stops the for each() loop
var next = nums[j];
// Get the value
var percentage = (Math.abs(0.5 - prev) < Math.abs(next - 0.5)) ? prev : next;
// Get the key from the value
$scope.seventyfive = parseInt('0' + Object.keys(nums).filter(filterPct(nums, percentage))[0], 10);
break;
}
}
But this is returning 0 instead of the right value. I am positive I am missing something obvious, but I obviously need another pair of eyes...
UPDATE: Thanks to the support I received, this is the error-proof version of the code above:
filterPct = function (nums, pct) {
return function (key) {
return nums[key] === pct;
};
};
// Store the value with 50% Confidence
for (i in nums) {
if (nums.hasOwnProperty(i)) {
if (0.5 > nums[i]) {
prev = nums[i];
} else if (0.5 <= nums[i]) {
// If the current number is equal to 0.5, or immediately higher, stores that number
// and stops the for each() loop
next = nums[i];
// Get the value
percentage = (Math.abs(0.5 - prev) < Math.abs(next - 0.5)) ? prev : next;
// Get the key from the value
$scope.fifty = parseInt('0' + Object.keys(nums).filter(filterPct(nums, percentage))[0], 10);
break;
}
}
}
filterPct = function (nums, pct) {
return function () {
return nums[key] === pct;
};
}
You forgot to define key (it should be the first argument of the inner function).
Assume we have an integer 16.
Is there a function, that returns random array of numbers, which compose its sum?
For example 7 1 2 4 1 1 or 1 5 2 3 6
I wonder if some elegant method of doing this in JavaScript exists.
No there's not existing function, but e.g.:
var n = 16;
var a = [];
while (n > 0) {
var s = Math.round(Math.random()*n);
a.push(s);
n -= s;
}
a contains the array.
you can consider this method too
function getRandomInt(max) {
return Math.floor(Math.random() * max + 1);
}
const total = 100;
const max = 20;
const nbrounds = 9;
function fillWithRandom(max, total, len) {
let arr = new Array();
let sum = 0;
newmax = max;
do {
newtotal = total - sum;
//max depending on length
console.log(arr.length,len);
if (arr.length+1 == len) {
arr.push(newtotal);
} else {
maxbylen = parseInt(newtotal / (len - arr.length));
// console.log('maxbylen', maxbylen, arr.length);
if (max > maxbylen) {
rndmax = max;
} else {
rndmax = maxbylen;
}
if (newtotal > max) {
rnd = getRandomInt(rndmax);
} else {
rnd = getRandomInt(newtotal);
}
arr.push(rnd);
}
sum = arr.reduce((acc, val) => acc + val, 0);
// console.log('sum', sum, 'newtotal', newtotal, 'rnd', rnd, arr);
} while (sum < total);
// console.log(arr);
//random order
return arr.map((value) => ({value, sort: Math.random()})).sort((a, b) => a.sort - b.sort).map(({ value }) => value);
}
;
console.log(fillWithRandom(max, total, nbrounds));