Backstory: when I was doing one of my side projects, one of the tasks was to display photos from Unspash API in multiple cards. Goal was to pick photos randomly without repeating them. I used good old Math.random()
to randomly pick photos from API's response. But the problem was that often few numbers were repeating, thus there were the same pictures in different cards.
Let's say you want to generate 5 random unique numbers from 1 to 10. Big chances that you'll get at least one repeated number.
Solution for this task is to replace each picked (random) number in array with another unused one.
In the code this would be something like this:
function randomUniqueNum(range, outputCount) {
let arr = []
for (let i = 1; i <= range; i++) {
arr.push(i)
}
let result = [];
for (let i = 1; i <= outputCount; i++) {
const random = Math.floor(Math.random() * (range - i));
result.push(arr[random]);
arr[random] = arr[range - i];
}
return result;
}
Let's look line by line.
Function takes range, and output count.
For instance randomUniqueNum(10, 5)
First we generate array from 1 to 10
let arr = []
for (let i = 1; i <= 10; i++) {
arr.push(i)
}
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Then we use another loop to pick numbers from this array.
Iterations in this loop equals to output count, in this case to 5.
Then we generate random number:
const random = Math.floor(Math.random() * (range - i))
Each iteration we decreasing range by 1.
Then using this random number as index in arr
we push it to the result array:
result.push(arr[random])
After that we replace 'used' number in arr
with the one from the end of the same array:
arr[random] = arr[range - i]
Even though in the next iteration Math.random()
will give us the same number, we'll get different result because we replaced it with the number from the end.
Since we decrease range in each iteration: range - i
so numbers from upper end of array will not be picked.
At the end we just return array of unique random numbers.
I hope this would help you in any way.
Top comments (3)
Nice. Here's another implementation using a
Set()
How's this solution work, though. And it's rather difficult to read. Would you break it down? I mean it looks handy...but
This is so cool! Gotta love new JS features