DEV Community

Sagdi Formanov
Sagdi Formanov

Posted on

8 1

Generate unique (non-repeating) random numbers

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;
}
Enter fullscreen mode Exit fullscreen mode

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)
  }
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

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])
Enter fullscreen mode Exit fullscreen mode

After that we replace 'used' number in arr with the one from the end of the same array:

arr[random] = arr[range - i]
Enter fullscreen mode Exit fullscreen mode

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.

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (3)

Collapse
 
shane325 profile image
Shane Barry • Edited

Nice. Here's another implementation using a Set()

const randomUnique = (range, count) => {
    let nums = new Set();
    while (nums.size < count) {
        nums.add(Math.floor(Math.random() * (range - 1 + 1) + 1));
    }
    return [...nums];
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
k16e profile image
Kabolobari Benakole

How's this solution work, though. And it's rather difficult to read. Would you break it down? I mean it looks handy...but

Collapse
 
sagdish profile image
Sagdi Formanov • Edited

This is so cool! Gotta love new JS features

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more