0

I need to put the numbers from low to high in an array randomly.

For example given: low = 10, high = 15 a result like [ 12, 13, 10, 14, 11] is good.

This is a simple algorithm: iterate from low to high and try to fill in the empty slots on an array.

const low = 1000
const high = 1010

const diff = high - low
const arr = new Array(diff)

for (var i = low; i < high; i++) {
  let success = false
  while(!success) {
    const index = Math.floor(Math.random() * diff)
    if (arr[index] === undefined) {
      arr[index] = i
      success = true
    }
    console.log(`${index} was ${success ? 'available' : 'taken'}`)
  }
}

console.log(arr)

The problem is: in the end where most of the elements are filled, it is harder to find an unoccupied slot in the array.

My question is: is there an algorithm that constantly generates unique new numbers until all the numbers are consumed?

Another way to think about it is an algorithm that shuffles an array the most efficient and quickest way.

AlexStack
  • 16,766
  • 21
  • 72
  • 104
  • 1
    No, not that I know of. If you want to generate true random numbers over a range, then there is always the chance of drawing a duplicate. If not, then you're not generating random numbers over that inclusive range. – Tim Biegeleisen Jul 05 '18 at 11:02
  • 1
    Instead of generating "random" numbers, generate a list of the numbers and shuffle it "randomly" by using something like [Fisher-Yates Shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle). – Sani Huttunen Jul 05 '18 at 11:03
  • Shuffle a list containing the range you want and pop elements off it – c2huc2hu Jul 05 '18 at 11:04
  • Note: If you cannot afford to store the array for shuffling, see https://stackoverflow.com/questions/3583697/generating-full-period-full-cycle-random-numbers-or-permutations-similar-to-lcg – Hans Olsson Jul 05 '18 at 11:50

3 Answers3

4

Instead of generating "random" numbers, generate a list of the numbers and shuffle it "randomly" by using something like Fisher-Yates Shuffle:

function getRandomArray(min, max) {
  return shuffle([...Array(max - min).keys()].map(i => i + min));
}

function shuffle(array) {
  var m = array.length, t, i;

  while (m) {

    i = Math.floor(Math.random() * m--);

    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }

  return array;
}

var randomArr = getRandomArray(10, 15);
console.log(randomArr);
Sani Huttunen
  • 23,620
  • 6
  • 72
  • 79
  • Here's a short version: `function g(m,x){return s([...Array(x-m).keys()].map(i=>i+m));} function s(a){var m=a.length,t,i;while(m){i=~~(Math.random()*m--);[a[m],a[i]]=[a[i],a[m]];}return a;}` – Sani Huttunen Jul 06 '18 at 14:21
0

Another implementation of Fisher-Yates Shuffle:

const low = 1000
const high = 1010
const delta = high - low
const arr = [...new Array(delta)]
arr.forEach((value, index, arr) => arr[index] = index + low)

const result = []
while (arr.length > 0) {
  const index = Math.floor(Math.random() * arr.length)
  result.push(arr[index])
  arr.splice(index, 1)
}

console.log(result)
AlexStack
  • 16,766
  • 21
  • 72
  • 104
  • Well... That doesn't make sense. You have `low = 1000` and `high = 1010` and generate an array of numbers from `0` to `9`. Although the length of the array is correct but the range is wrong. You need to change `result.push(arr[index])` to `result.push(arr[index] + low);` – Sani Huttunen Jul 05 '18 at 12:06
  • Thank you. fixed! – AlexStack Jul 05 '18 at 12:23
0

For someone looking this in java, just use Collections API.

We have:

Collections.shuffle(yourOriginalArray);
Shanu Gupta
  • 3,699
  • 2
  • 19
  • 29