I like commenter @YuriyGalanter's idea of choosing items randomly until all are taken and only then repeating, so here's an implementation:
function randomNoRepeats(array) {
var copy = array.slice(0);
return function() {
if (copy.length < 1) { copy = array.slice(0); }
var index = Math.floor(Math.random() * copy.length);
var item = copy[index];
copy.splice(index, 1);
return item;
};
}
var chooser = randomNoRepeats(['Foo', 'Bar', 'Gah']);
chooser(); // => "Bar"
chooser(); // => "Foo"
chooser(); // => "Gah"
chooser(); // => "Foo" -- only repeats once all items are exhausted.
Answer from maerics on Stack OverflowI like commenter @YuriyGalanter's idea of choosing items randomly until all are taken and only then repeating, so here's an implementation:
function randomNoRepeats(array) {
var copy = array.slice(0);
return function() {
if (copy.length < 1) { copy = array.slice(0); }
var index = Math.floor(Math.random() * copy.length);
var item = copy[index];
copy.splice(index, 1);
return item;
};
}
var chooser = randomNoRepeats(['Foo', 'Bar', 'Gah']);
chooser(); // => "Bar"
chooser(); // => "Foo"
chooser(); // => "Gah"
chooser(); // => "Foo" -- only repeats once all items are exhausted.
Whenever an item is selected, move it to the back of the array and randomly select from a slice of the original array array.slice(0, -5).
var a = ["Roger", "Russell", "Clyde", "Egbert", "Clare", "Bobbie", "Simon", "Elizabeth", "Ted", "Caroline"];
var chooseName = function () {
num = Math.floor(Math.random() * a.length - 5);
name = a.splice(num,1);
a.push(name);
}
window.addEventListener("keypress", function (e) {
var keycode = e.keyCode;
if (keycode == 13) {
chooseName();
}
}, false);
EDIT: This also has the side-effect of not giving whichever variables happen to tail the list the unfair disadvantage that they won't be considered in the first N calls. If that's a problem for you, maybe try hold a static variable somewhere to keep track of the size of the slice to use and max it out at B (in this case, 5). e.g.
var a = ["Roger", "Russell", "Clyde", "Egbert", "Clare", "Bobbie", "Simon", "Elizabeth", "Ted", "Caroline"];
B = 5; //max size of 'cache'
N = 0;
var chooseName = function () {
num = Math.floor(Math.random() * a.length - N);
N = Math.min(N + 1, B);
name = a.splice(num,1);
a.push(name);
}
Hi! I'm stuck on a problem, and not quite sure how to solve it. I need to randomly select elements from an array, until every element has been selected, but no element can be repeated. Finally, after every element has been selected, it can start over.
I'm able to get it randomly select elements from array, and do the entire thing without repeating by splicing out the selected element, but I'm sure that's not right if I want to start over again once every element has been selected.
How to make Math.random not repeat same numbers
Random item from array with no repeat using javascript? - Stack Overflow
Random Image with No Repeats - JavaScript - SitePoint Forums | Web Development & Design Community
javascript - Random array of numbers without repeating - oojs practice - Code Review Stack Exchange
var a = ["Mango","Orange","Banana","Apple","Grapes","Berry","Peach"];
function searchRandom(count, arr){
let answer = [], counter = 0;
while(counter < count){
let rand = arr[Math.floor(Math.random() * arr.length)];
if(!answer.some(an => an === rand)){
answer.push(rand);
counter++;
}
}
return answer;
}
console.log(searchRandom(3,a))
Making it flexible to support any count you want and ensured uniqueness
var a = ["Mango","Orange","Banana","Apple","Grapes","Berry","Peach"]
var res = a.sort(function() {
return 0.5 - Math.random();
});
console.log(res.slice(a,3))
Dyalog APL, 1 byte
?
Just a builtin. Try it here.
JavaScript (ES6), 68 66 bytes
n=>r=>G=(s=new Set)=>s.size<n?G(s.add(Math.random()*r+1|0)):[...s]
Called as F(N)(R)(), where F is the function assignment, and N/R are the values.
You asked for shorter than 73 bytes in Js ;)
EDIT: The answer by @C5H8NNaO4 works within the fact that the rules don't specify the values must be uniform across 1..R. Given that, here's a version works in 63 bytes (called as F(R)(N)):
r=>G=(n,s=[])=>n--?G((s[n]=n+1,n),s):s.sort(a=>new Date/a%1-.5)
If I understand right then you're just looking for a permutation (i.e. the numbers randomised with no repeats) of the numbers 1-10? Maybe try generating a randomised list of those numbers, once, at the start, and then just working your way through those?
This will calculate a random permutation of the numbers in nums:
var nums = [1,2,3,4,5,6,7,8,9,10],
ranNums = [],
i = nums.length,
j = 0;
while (i--) {
j = Math.floor(Math.random() * (i+1));
ranNums.push(nums[j]);
nums.splice(j,1);
}
So, for example, if you were looking for random numbers between 1 - 20 that were also even, then you could use:
nums = [2,4,6,8,10,12,14,16,18,20];
Then just read through ranNums in order to recall the random numbers.
This runs no risk of it taking increasingly longer to find unused numbers, as you were finding in your approach.
EDIT: After reading this and running a test on jsperf, it seems like a much better way of doing this is a Fisher–Yates Shuffle:
function shuffle(array) {
var i = array.length,
j = 0,
temp;
while (i--) {
j = Math.floor(Math.random() * (i+1));
// swap randomly chosen element with current element
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
var ranNums = shuffle([1,2,3,4,5,6,7,8,9,10]);
Basically, it's more efficient by avoiding the use of 'expensive' array operations.
BONUS EDIT: Another possibility is using generators (assuming you have support):
function* shuffle(array) {
var i = array.length;
while (i--) {
yield array.splice(Math.floor(Math.random() * (i+1)), 1)[0];
}
}
Then to use:
var ranNums = shuffle([1,2,3,4,5,6,7,8,9,10]);
ranNums.next().value; // first random number from array
ranNums.next().value; // second random number from array
ranNums.next().value; // etc.
where ranNums.next().value will eventually evaluate to undefined once you've run through all the elements in the shuffled array.
Overall this won't be as efficient as the Fisher–Yates Shuffle because you're still splice-ing an array. But the difference is that you're now doing that work only when you need it rather than doing it all upfront, so depending upon your use case, this might be better.
//random number without repetition in JavaScript, Just in one line;
//it can be used as _id;
//it not need to store or check;
const myRnId = () => parseInt(Date.now() * Math.random());
console.log(myRnId()); // any random number included timeStamp;
Try this (splice removes the selected element from the source array) :
var r = [];
for (var i = 0; i < 5; i++) {
r.push(itemp.splice(
Math.floor(Math.random() * itemp.length), 1
)[0]);
}
alert(r);
You can check below code:
var nums = ["#jpId1", "#jpId2", "#jpId3", "#jpId4", "#jpId5", "#jpId6", "#jpId7","#jpId8", "#jpId9", "#jpId10", "#jpId11"],
ranNums = [],
i = 5,
j = 0;
k = 10;
while (i--) {
j = Math.floor(Math.random() * (k+1));
ranNums.push(nums[j]);
nums.splice(j,1);
k--;
}
console.log(ranNums);
And you can find link here http://jsfiddle.net/8Xb5g/1/
Generate a range of numbers:
var numbers = [1, 2, 3, 4];
And then shuffle it:
function shuffle(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 random = shuffle(numbers);
One more way to do it:
for (var a = [0, 1, 2, 3, 4], i = a.length; i--; ) {
var random = a.splice(Math.floor(Math.random() * (i + 1)), 1)[0];
console.log(random);
}
Don't know if it's even possible to make it more compact.
Tests: http://jsfiddle.net/2m3mS/1/
Here is embed demo:
$('button').click(function() {
$('.output').empty();
for (var a = [0, 1, 2, 3, 4], i = a.length; i--; ) {
var random = a.splice(Math.floor(Math.random() * (i + 1)), 1)[0];
$('.output').append('<span>' + random + '</span>');
}
}).click();
.output span {
display: inline-block;
background: #DDD;
padding: 5px;
margin: 5px;
width: 20px;
height: 20px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="output"></div>
<button>Run</button>