2

I need help with writing some code that will create a random number from an array of 12 numbers and print it 9 times without dupes. This has been tough for me to accomplish. Any ideas?

Yi Jiang
  • 49,435
  • 16
  • 136
  • 136
Vic
  • 23
  • 1
  • 1
  • 3

7 Answers7

9

var nums = [1,2,3,4,5,6,7,8,9,10,11,12];
var gen_nums = [];

function in_array(array, el) {
   for(var i = 0 ; i < array.length; i++) 
       if(array[i] == el) return true;
   return false;
}

function get_rand(array) {
    var rand = array[Math.floor(Math.random()*array.length)];
    if(!in_array(gen_nums, rand)) {
       gen_nums.push(rand); 
       return rand;
    }
    return get_rand(array);
}

for(var i = 0; i < 9; i++) {
    console.log(get_rand(nums));
}
uingtea
  • 6,002
  • 2
  • 26
  • 40
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • question: how to repeat this script for 20 time? – sundsx Jan 03 '20 at 14:29
  • 1
    I downvoted because this has an unpredicable run-time, doesn't handle duplicates in the source array gracefully, and in the pathological case, will blow the call stack. This isn't how to solve this problem. – spender Mar 30 '22 at 11:20
4

The most effective and efficient way to do this is to shuffle your numbers then print the first nine of them. Use a good shuffle algorithm.What Thilo suggested will give you poor results. See here.

Edit Here's a brief Knuth Shuffle algorithm example:


void shuffle(vector<int> nums)
{
  for (int i = nums.size()-1; i >= 0; i--)
  {
    // this line is really shorthand, but gets the point across, I hope.
    swap(nums[i],nums[rand()%i]);
  }
}
JoshD
  • 12,490
  • 3
  • 42
  • 53
  • Using the proven algorithms you suggest does seem like a better idea if one is serious about it. I'd just like to point out that the algorithm I suggested is not the one discussed unfavourably in "see here". – Thilo Sep 26 '10 at 06:58
  • It isn't the same algorithm, no. But I fear it would still produce the same error if I understand right. There are n^3 outcomes for your algorithm that will land in one of n! boxes. That cannot give an even distribution. Try the experiment in the article with your algorithm and see if it works. – JoshD Sep 26 '10 at 07:06
  • In the comments to the blog you linked, "my" algorithm is brought up by "fabio". He claims that it works, but with a bigger number of swaps (not just the array size). I'll read up on it a little more, and see if I can prove it right or wrong. Andrew Dunn's proposal below seems statistically correct, too, even though it has performance problems. – Thilo Sep 26 '10 at 07:20
  • I looked at that comment you pointed out. I still feel that the number of paths must be divisible by n! to fit evenly into n! outcomes, but I may be mistaken. I'd be interested to see what you find comparing Knuth's algorithm to yours side by side. And yes, Dunn's algorithm should work (despite performance). – JoshD Sep 26 '10 at 07:35
  • I am taking it to the statisticians: http://stats.stackexchange.com/questions/3082/what-is-wrong-with-this-naive-shuffling-algorithm – Thilo Sep 26 '10 at 07:39
  • Cool. I'll keep my eyes on it. Thanks! Maybe add a link to the Coding Horror article? :) – JoshD Sep 26 '10 at 07:43
0

Here is a generic way of getting random numbers between min and max without duplicates:

function inArray(arr, el) {
    for(var i = 0 ; i < arr.length; i++) 
            if(arr[i] == el) return true;
    return false;
}

function getRandomIntNoDuplicates(min, max, DuplicateArr) {
    var RandomInt = Math.floor(Math.random() * (max - min + 1)) + min;
    if (DuplicateArr.length > (max-min) ) return false;  // break endless recursion
    if(!inArray(DuplicateArr, RandomInt)) {
       DuplicateArr.push(RandomInt); 
       return RandomInt;
    }
    return getRandomIntNoDuplicates(min, max, DuplicateArr); //recurse
}

call with:

var duplicates  =[];
for (var i = 1; i <= 6 ; i++) { 
    console.log(getRandomIntNoDuplicates(1,10,duplicates));
}
cologne
  • 41
  • 6
0

If I understand you correctly, you want to shuffle your array.

Loop a couple of times (length of array should do), and in every iteration, get two random array indexes and swap the two elements there. (Update: if you are really serious about this, this may not be the best algorithm).

You can then print the first nine array elements, which will be in random order and not repeat.

Thilo
  • 257,207
  • 101
  • 511
  • 656
0

This is relatively simple to do, the theory behind it is creating another array which keeps track of which elements of the array you have used.

var tempArray = new Array(12),i,r;
for (i=0;i<9;i++)
    {
    r = Math.floor(Math.random()*12);    // Get a random index
    if (tempArray[r] === undefined)      // If the index hasn't been used yet
        {
        document.write(numberArray[r]);  // Display it
        tempArray[r] = true;             // Flag it as have been used
        }
    else                                 // Otherwise
        {
        i--;                             // Try again
        }
    }

Other methods include shuffling the array, removing used elements from the array, or moving used elements to the end of the array.

Randy the Dev
  • 25,810
  • 6
  • 43
  • 54
  • Don't use the above code for professional works though, it is an extremely simple example used to demonstrate the logic behind what you are trying to do (printing 9 values from an array of 12 values in random order). – Randy the Dev Sep 26 '10 at 06:40
  • It does seem to produce an unbiased sequence of numbers, though. The only problem I can see is performance as it gets increasingly more difficult to find the remaining numbers. – Thilo Sep 26 '10 at 07:02
  • Exactly, while that algorithm will suffice for smaller sets of data, for larger sets, you need to make sure collisions don't occur, either by removing data from the array, or pushing it to the end. – Randy the Dev Sep 26 '10 at 07:15
0

Try this once:

//Here o is the array;
var testArr = [6, 7, 12, 15, 17, 20, 21];
    shuffle = function(o){ //v1.0
                        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;
                };
shuffle(testArr);
Sudhir Bastakoti
  • 99,167
  • 15
  • 158
  • 162
0
const nums = [1,2,3,4,5,6,7,8,9,10,11,12];
for(var i = 1 ; i < 10; i++){
    result = nums[Math.floor(Math.random()*nums.length)];
    const index = nums.indexOf(result);
    nums.splice(index, 1);
    console.log(i+' - '+result);
}
  • 1
    The community [encourages](https://meta.stackoverflow.com/questions/392712) adding explanations alongisde code, rather than purely code-based answers. As explained [here](https://meta.stackoverflow.com/questions/300837): "While this code may answer the question, providing additional context regarding *why* and/or *how* this code answers the question improves its long-term value." – costaparas Feb 21 '21 at 00:08