Getting Random Unique From Array
Solution 1:
Implementing this as a generator makes it pretty nice to work with. Note, this implementation differs from ones that require the entire input array to be shuffled first.
This
sample
function works lazily, giving you 1 random item per iteration up toN
items you ask for. This is nice because if you just want 3 items from a list of 1000, you don't have to touch all 1000 items first.
// sample :: Integer -> [a] -> [a]constsample = n => function* (xs) {
let ys = xs.slice(0);
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield ys.splice(i,1)[0];
n--; len--;
}
}
// example inputslet items = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// get 3 random itemsfor (let i ofsample(3) (items))
console.log(i); // f g c// partial applicationconst lotto = sample(3);
for (let i oflotto(numbers))
console.log(i); // 3 8 7// shuffle an arrayconstshuffle = xs => Array.from(sample (Infinity) (xs))
console.log(shuffle(items)) // [b c g f d e a]
I chose to implement sample
in a way that does not mutate the input array, but you could easily argue that a mutating implementation is favourable.
For example, the shuffle
function might wish to mutate the original input array. Or you might wish to sample from the same input at various times, updating the input each time.
// sample :: Integer -> [a] -> [a]constsample = n => function* (xs) {
let len = xs.length;
while (n > 0 && len > 0) {
let i = (Math.random() * len) >> 0;
yield xs.splice(i,1)[0];
n--; len--;
}
}
// deal :: [Card] -> [Card]constdeal = xs => Array.from(sample (2) (xs));
// setup a deck of cards (13 in this case)// cards :: [Card]let cards = 'A234567890JQK'.split('');
// deal 6 players 2 cards each// players :: [[Card]]let players = Array.from(Array(6), $=> deal(cards))
console.log(players);
// [K, J], [6, 0], [2, 8], [Q, 7], [5, 4], [9, A]// `cards` has been mutated. only 1 card remains in the deckconsole.log(cards);
// [3]
sample
is no longer a pure function because of the array input mutation, but in certain circumstances (demonstrated above) it might make more sense.
Another reason I chose a generator instead of a function that just returns an array is because you may want to continue sampling until some specific condition.
Perhaps I want the first prime number from a list of 1,000,000 random numbers.
- "How many should I sample?" – you don't have to specify
- "Do I have to find all the primes first and then select a random prime?" – Nope.
Because we're working with a generator, this task is trivial
const randomPrimeNumber = listOfNumbers => {
for (let x of sample(Infinity) (listOfNumbers)) {
if (isPrime(x))
return x;
}
return NaN;
}
This will continuously sample 1 random number at a time, x
, check if it's prime, then return x
if it is. If the list of numbers is exhausted before a prime is found, NaN
is returned.
Solution 2:
Here you go. Simple code.
var random = 0, cars = ["Saab", "Volvo", "BMW"], newCars = [];
while (newCars.length < 3) {
random = Math.floor(Math.random() * 3);
if (newCars.indexOf(cars[random]) == -1) {
newCars.push(cars[random]);
}
}
console.log(newCars);
Solution 3:
Try this:
functionRandomUnique(inputArray){
var ia = inputArray;
if(!(ia instanceofArray)){
thrownewError('inputArray must be an instanceof Array');
}
this.unique = function(){
return ia.splice(Math.random()*ia.length, 1)[0];
}
this.getArray = function(){
return ia;
}
}
var ru = newRandomUnique(yourArray);
console.log(ru.unique());
console.log(ru.unique());
Post a Comment for "Getting Random Unique From Array"