Random Selection from Array into new Array - javascript

I have seen this question answered here, but I have an additional question that is related.
Im trying to achieve:
the same thing, but, with the output being a selection of more than 1 number, the above works fine if you only want a single value returned.
How can I return (x) amount of outputs #7 in this case into a new var or array ...? Some guidance on best practice will also be appreciated ;)
Thanks a bunch....
Just for fun,
Objective:
Create a teeny weenie web App that returns 7 variable numbers in a range [ 1 - 49 ] into an array.
`
Think return a list of Lotto Numbers
Create new array from selection using _underscore.js [Sample function]
**** I know this is easier, but im trying to get an understanding
of using Vanilla JS to accomplish this
_.sample([1, 2, 3, 4, 5, 6], 3); => [1, 6, 2]
var getLoot = Array.from(Array(50).keys()) // Create array of 49 numbers.
console.info(getLoot);
var pick = getLoot[Math.floor(Math.random() * getLoot.length)];
pick;
// pick returns a single which is fine if you want a single but, ..
// I want something like this :
var pick = function() {
// code that will return 7 numbers from the array into a new Array
// will randomize every time pick is called...
}

If you want to return more than just 1 value you can store your results into a data structure like an array. Here is a solution to the problem
assuming you can pass in your array of 50 numbers into the pick() funciton.:
var getRandomArbitrary = function(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
var pick = function(fiftyNumberArray, numberOfValuesWanted) {
var randomNums = [];
for(var i = 0; i < numberOfValuesWanted; i++) {
randomNums.push(
fiftyNumberArray[getRandomArbitrary(0, 50)]
);
}
return randomNums;
};
var fiftyNumbers = [] // <- set your array of fifty numbers
pick(fiftyNumbers, 7);
Javascript's Math.random() will return a value in between 0 and 1 (exclusive). So to get an index scaled up to the correct value to look into your array, you would want to multiply that by the formula (max - min) + min

You can use Array.prototype.splice(), Math.floor(), Math.random(), for loop to remove elements from input array, return an array containing pseudo randomly picked index from input array without duplicate indexes being selected.
function rand(n) {
var res = []; var a = Array.from(Array(n).keys());
for (;a.length;res.push(a.splice(Math.floor(Math.random()*a.length),1)[0]));
return res
}
console.log(rand(50));

One good way of doing this job is shuffling the array and picking the first n values. Such as;
function shuffle(a){
var i = a.length,
j,
tmp;
while (i > 1) {
j = Math.floor(Math.random()*i--);
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
return a;
};
var arr = Array(50).fill().map((_,i) => i+1); //[1,2,3...49,50]
randoms = shuffle(arr).slice(0,7) // to get 7 random numbers from arrary arr
console.log(randoms)

This is probably what you want.
$(function()
{
var lol = [1,4,5,6,7,8,9];
function getPart(array,number)
{
var part = [],
index;
while(true)
{
if(part.length == number)
{
break;
}
index = $.random(0,part.length);
part.push(lol.splice(index,1));
}
return part;
}
});
$.random = function(min,max,filter)
{
var i,
n = Math.floor(Math.random()*(max-min+1)+min);
if(filter != undefined && filter.constructor == Array)
{
for(i=filter.length-1;i>-1;i--)
{
if(n == filter[i])
{
n = Math.floor(Math.random()*(max-min+1)+min)
i = filter.length;
}
}
}
return n;
}

Related

Return value from an array based on input that fits between two steps of another array

I start off with two arrays like this
const colors = ["#00876c", "#50a26f", "#88bb72", "#c1d379", "#fde987", "#fac067", "#f49654", "#e86b4e", "#d43d51"];
const steps = [13.5, 13.6875, 13.875, 14.0625, 14.25, 14.4375, 14.625, 14.8125, 15];
Both the colors array and steps array have the same length, so you can interpret it as each step associating with the color at the given index.
What I'm trying to do is, based on the value of an input, fit it between the steps and associate said input with its color.
For example:
returnColor(13.2) // returns #00876c
returnColor(20) // returns #d43d51
returnColor(13.7) // returns #50a26f
returnColor(14.5) // returns #fac067
Feel free to ask any question if I haven't explained quite well.
You can use the closest function from this answer to get the index which is most similar to the input provided.
const colors = ["#00876c", "#50a26f", "#88bb72", "#c1d379", "#fde987", "#fac067", "#f49654", "#e86b4e", "#d43d51"];
const steps = [13.5, 13.6875, 13.875, 14.0625, 14.25, 14.4375, 14.625, 14.8125, 15];
//get the index of the element which is closest to the step
function closest(num, arr) {
var curr = arr[0],
diff = Math.abs(num - curr),
index = 0;
for (var val = 0; val < arr.length; val++) {
let newdiff = Math.abs(num - arr[val]);
if (newdiff < diff) {
diff = newdiff;
curr = arr[val];
index = val;
}
}
return index;
}
function returnColor(step) {
const index = closest(step, steps);
return colors[index];
}
//Tests
console.log(returnColor(13.2)); // returns #00876c
console.log(returnColor(20)); // returns #d43d51
console.log(returnColor(13.7)); // returns #50a26f
console.log(returnColor(14.5)); // returns #fac067

subSetSum - powerSum JS . concatenating arrays into subset

With my very poor js knowledge, I am trying to solve the powerSum algorithm.Where I am supposed to return the count of the ways a number X can be expressed as the sum of the Nth powers of unique, natural numbers...
I have -somehow- got to the point where I can see my subsets printed out on the console but I haven't been able to figure out how to concatenate the result of my 'subsetSum' function to my 'subsets' variable so I can return my result as an array of arrays. The only way I get to have any returning value is if I concat my subsets into a STRING. and that is not what I am expecting. Here is my code.
// returns an array with all the results of natural numbers elevated
//to the nth power <= X
function powersLessThan(x,power){
let newArr = [];
for(var i = 1; i < x; i+=1){
var powered = Math.pow(i,power);
if (powered <= x){
newArr.push(powered);
}else if (powered > x){
break;
}
}
return newArr;
}
// returns an array of all the possible combinations of numbers that sum to X
function subsetsSum(numbersArr,target,partialSum){
var sum,n,remaining;
var subsets = [];
partialSum = partialSum || [];
sum = partialSum.reduce(function (a,b){
return a + b;
},0);
if (sum === target){
return partialSum; // this is my base case. datatype = object. Not sure why... ??
}
for (var i = 0; i < numbersArr.length; i+=1){
n = numbersArr[i];
remaining = numbersArr.slice( i + 1);
subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
}
return subsets;
}
console.log(subsetsSum(powersLessThan(100,2),100)); // with this my ooutput
is ' 1,9,16,25,4936,64100' instead of => [[1,9,16,25,49],[64,36],[100]] :/
The final count will be the length of the array above .. when it works..
Thanks for your help.
Change:
return partialSum;
To:
return [partialSum];
And change:
subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
To:
subsets = subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
(You could also just use, subsets.push(...))

Pick m integers randomly from an array of size n in JS

Problem (from Cracking the Coding Interview): Write a method to randomly generate a set of m integers from an array of size n.
Each element must have equal probability of being chosen.
I'm implementing my answer in JS. For the recursive function, the code sometimes returns undefined as one of the elements in the array.
My JS Code
var pickMRecursively = function(A, m, i) {
if (i === undefined) return pickMRecursively(A, m, A.length);
if (i+1 === m) return A.slice(0, m);
if (i + m > m) {
var subset = pickMRecursively(A, m, i-1);
var k = rand(0, i);
if (k < m) subset[k] = A[i];
return subset;
}
return null;
};
Given Java Solution
int[] pickMRecursively(int[] original, int m,int i) {
if (i +1==m){// Basecase
/* return first m elements of original */
} elseif(i+m>m){
int[] subset = pickMRecursively(original, m, i - 1);
int k = random value between 0 and i, inclusive
if(k<m){
subset[k] = original[i]j
}
return subset;
}
return null;
}
I hate these questions because sometime they're often deliberately vague - I'd ask "What type of data is in the array?". But if this is actually a question about randomly re-ordering an array, then in JavaScript, given that arr is an array of numbers, of which some/all might not be integers...
function generateM(arr) {
var hold = [];
var m = [];
var n = arr.length;
var grab;
// clone arr >> hold
while(n--) {
hold[n] = arr[n];
}
n = hold.length;
// select randomly from hold
while(n--) {
grab = hold.splice(Math.floor(Math.random()*n),1)[0];
// ensure integers
m.push(Math.round(grab));
}
return m;
}
The array arr is cloned here to cover scoping issues and to produce a fresh collection, not reorder an existing one.
ADDIT: Alternatively, if this is just asking for a set of m.length random integers generated from an array of n.length, then it doesn't matter what the content of the array actually is and the range of possible (randomly generated) values will be (could be?) 0 - n.length, so...
function generateM(arr, M) {
var aLen = arr.length;
var m = [];
do {
m.push(Math.round(Math.random() * aLen));
} while(M--);
return m;
}
...but that seems like a stupid, pointless challenge. The data in the 'array of size n' is quite important here it seems to me.

JavaScript: how to stop a random number from appearing twice

How can you, in using a random number generator, stop a number from appearing if it has already appeared once?
Here is the current code:
var random = Math.ceil(Math.random() * 24);
But the numbers appear more than once.
You can use an array of possible values ( I think in your case it will be 24 ) :
var values = [];
for (var i = 1; i <= 24; ++i){
values.push(i);
}
When you want to pick a random number you just do:
var random = values.splice(Math.random()*values.length,1)[0];
If you know how many numbers you want then it's easy, first create an array:
var arr = [];
for (var i = 0; i <= 24; i++) arr.push(i);
Then you can shuffle it with this little function:
function shuffle(arr) {
return arr.map(function(val, i) {
return [Math.random(), i];
}).sort().map(function(val) {
return val[1];
});
}
And use it like so:
console.log(shuffle(arr)); //=> [2,10,15..] random array from 0 to 24
You can always use an hashtable and before using the new number, check if it is in there or not. That would work for bigger numbers. Now for 24, you can always shuffle an array.
You could put the numbers you generate in an array and then check against that. If the value is found, try again:
var RandomNumber = (function()
{
// Store used numbers here.
var _used = [];
return {
get: function()
{
var random = Math.ceil(Math.random() * 24);
for(var i = 0; i < _used.length; i++)
{
if(_used[i] === random)
{
// Do something here to prevent stack overflow occuring.
// For example, you could just reset the _used list when you
// hit a length of 24, or return something representing that.
return this.get();
}
}
_used.push(random);
return random;
}
}
})();
You can test being able to get all unique values like so:
for(var i = 0; i < 24; i++)
{
console.log( RandomNumber.get() );
}
The only issue currently is that you will get a stack overflow error if you try and get a random number more times than the amount of possible numbers you can get (in this case 24).

math random number without repeating a previous number

Can't seem to find an answer to this, say I have this:
setInterval(function() {
m = Math.floor(Math.random()*7);
$('.foo:nth-of-type('+m+')').fadeIn(300);
}, 300);
How do I make it so that random number doesn't repeat itself. For example if the random number is 2, I don't want 2 to come out again.
There are a number of ways you could achieve this.
Solution A:
If the range of numbers isn't large (let's say less than 10), you could just keep track of the numbers you've already generated. Then if you generate a duplicate, discard it and generate another number.
Solution B:
Pre-generate the random numbers, store them into an array and then go through the array. You could accomplish this by taking the numbers 1,2,...,n and then shuffle them.
shuffle = function(o) {
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
var randorder = shuffle([0,1,2,3,4,5,6]);
var index = 0;
setInterval(function() {
$('.foo:nth-of-type('+(randorder[index++])+')').fadeIn(300);
}, 300);
Solution C:
Keep track of the numbers available in an array. Randomly pick a number. Remove number from said array.
var randnums = [0,1,2,3,4,5,6];
setInterval(function() {
var m = Math.floor(Math.random()*randnums.length);
$('.foo:nth-of-type('+(randnums[m])+')').fadeIn(300);
randnums = randnums.splice(m,1);
}, 300);
You seem to want a non-repeating random number from 0 to 6, so similar to tskuzzy's answer:
var getRand = (function() {
var nums = [0,1,2,3,4,5,6];
var current = [];
function rand(n) {
return (Math.random() * n)|0;
}
return function() {
if (!current.length) current = nums.slice();
return current.splice(rand(current.length), 1);
}
}());
It will return the numbers 0 to 6 in random order. When each has been drawn once, it will start again.
could you try that,
setInterval(function() {
m = Math.floor(Math.random()*7);
$('.foo:nth-of-type(' + m + ')').fadeIn(300);
}, 300);
I like Neal's answer although this is begging for some recursion. Here it is in java, you'll still get the general idea. Note that you'll hit an infinite loop if you pull out more numbers than MAX, I could have fixed that but left it as is for clarity.
edit: saw neal added a while loop so that works great.
public class RandCheck {
private List<Integer> numbers;
private Random rand;
private int MAX = 100;
public RandCheck(){
numbers = new ArrayList<Integer>();
rand = new Random();
}
public int getRandomNum(){
return getRandomNumRecursive(getRand());
}
private int getRandomNumRecursive(int num){
if(numbers.contains(num)){
return getRandomNumRecursive(getRand());
} else {
return num;
}
}
private int getRand(){
return rand.nextInt(MAX);
}
public static void main(String[] args){
RandCheck randCheck = new RandCheck();
for(int i = 0; i < 100; i++){
System.out.println(randCheck.getRandomNum());
}
}
}
Generally my approach is to make an array containing all of the possible values and to:
Pick a random number <= the size of the array
Remove the chosen element from the array
Repeat steps 1-2 until the array is empty
The resulting set of numbers will contain all of your indices without repetition.
Even better, maybe something like this:
var numArray = [0,1,2,3,4,5,6];
numArray.shuffle();
Then just go through the items because shuffle will have randomized them and pop them off one at a time.
Here's a simple fix, if a little rudimentary:
if(nextNum == lastNum){
if (nextNum == 0){nextNum = 7;}
else {nextNum = nextNum-1;}
}
If the next number is the same as the last simply minus 1 unless the number is 0 (zero) and set it to any other number within your set (I chose 7, the highest index).
I used this method within the cycle function because the only stipulation on selecting a number was that is musn't be the same as the last one.
Not the most elegant or technically gifted solution, but it works :)
Use sets. They were introduced to the specification in ES6. A set is a data structure that represents a collection of unique values, so it cannot include any duplicate values. I needed 6 random, non-repeatable numbers ranging from 1-49. I started with creating a longer set with around 30 digits (if the values repeat the set will have less elements), converted the set to array and then sliced it's first 6 elements. Easy peasy. Set.length is by default undefined and it's useless that's why it's easier to convert it to an array if you need specific length.
let randomSet = new Set();
for (let index = 0; index < 30; index++) {
randomSet.add(Math.floor(Math.random() * 49) + 1)
};
let randomSetToArray = Array.from(randomSet).slice(0,6);
console.log(randomSet);
console.log(randomSetToArray);
An easy way to generate a list of different numbers, no matter the size or number:
function randomNumber(max) {
return Math.floor(Math.random() * max + 1);
}
const list = []
while(list.length < 10 ){
let nbr = randomNumber(500)
if(!list.find(el => el === nbr)) list.push(nbr)
}
console.log("list",list)
I would like to add--
var RecordKeeper = {};
SRandom = function () {
currTimeStamp = new Date().getTime();
if (RecordKeeper.hasOwnProperty(currTimeStamp)) {
RecordKeeper[currTimeStamp] = RecordKeeper[currTimeStamp] + 1;
return currTimeStamp.toString() + RecordKeeper[currTimeStamp];
}
else {
RecordKeeper[currTimeStamp] = 1;
return currTimeStamp.toString() + RecordKeeper[currTimeStamp];
}
}
This uses timestamp (every millisecond) to always generate a unique number.
you can do this. Have a public array of keys that you have used and check against them with this function:
function in_array(needle, haystack)
{
for(var key in haystack)
{
if(needle === haystack[key])
{
return true;
}
}
return false;
}
(function from: javascript function inArray)
So what you can do is:
var done = [];
setInterval(function() {
var m = null;
while(m == null || in_array(m, done)){
m = Math.floor(Math.random()*7);
}
done.push(m);
$('.foo:nth-of-type('+m+')').fadeIn(300);
}, 300);
This code will get stuck after getting all seven numbers so you need to make sure it exists after it fins them all.

Categories