0

so I know this questing has been asked, but all the answers that were given are already known to me. I don't want to make a variable of all the posible numbers (that was always the answer). So to go to the question, I want to make a random number generator, that will generate me 7 numbers, that must not be the same. For example, I get random numbers: "5,16,12,5,21,37,2" ... But I don't want the number 5 to be used again, so I want different numbers. I made a code for the generation, but I can not think of any good method/way to do this. I was thinking that maybe check if the number is already in array and if it is, then generate another number, but as I'm amateur in JavaScript, I don't know how to do this. So here is my JavaScript code:

// JavaScript Document

function TableOn()
{
    document.write("<table border='1'>");
}
function TableOff()
{
    document.write("</table>");
}

function RandNum()
{
    var n = new Array();
    for(var i=0;i<7;i++)
    {
        n[i] = Math.round((1+(Math.random()*40)));
    }
    TableOn();
    for(var c=0;c<7;c=c+1)
    {
        document.write("<tr><td>"+n[c]+"</td></tr>");
    }
    TableOff();
}

In HTML I just have a button, that is onclick="RandNum()" ... Pardon for my English.

sesmajster
  • 752
  • 7
  • 32
  • **Why** don't you want to enumerate all the possible values and then shuffle them? It's OK if you have requirements that conflict with that approach, but you have to explain them or else we have no idea what the real problem is. – Pointy Mar 19 '14 at 15:38
  • I just don't want to use this approach. What if I want to have 7 numbers, that can go up to 1000... Go ahead and write 1000 numbers... I'm sure this can be done elsehow... – sesmajster Mar 19 '14 at 15:41
  • Do what you want, but if you use the "check for duplicates" approach and the range of values is close to the number of values, performance will be terrible. – Pointy Mar 19 '14 at 16:30

6 Answers6

1

I would do it like this:

var nums = [], numsLen = 5, maxNum = 100, num;
while (nums.length < numsLen) {
    num = Math.round(Math.random() * maxNum);
    if (nums.indexOf(num) === -1) {
        nums.push(num);
    }
}

This generates an array with 5 random numbers in the range 0..100. (numsLen cannot be greater than maxNum.)

zord
  • 4,538
  • 2
  • 25
  • 30
  • 2
    This is a generally very bad algorithm. The average running time will explode the more you move `numsLen` to `100`. – Ingo Bürk Mar 19 '14 at 15:51
  • @IngoBürk: Of course, this is not to be used for big arrays. But for small arrays it's a clean and simple solution. – zord Mar 19 '14 at 15:56
  • my answer contains ur answer as part of my answer, I also provided an alternative method that runs at lower complexity but higher memory usage. Also made them into functions for flexible usage :) – Populus Mar 19 '14 at 16:15
  • 1
    Using `.indexOf()` instead of maintaining a "map" object makes this even slower than it would otherwise be. – Pointy Mar 19 '14 at 16:25
0

These commands can be used to check if a value is/is not in your array:

if ( !!~n.indexOf(someVal) ) {
    // someVal is in array "n"
}
if ( !~n.indexOf(someVal) ) {
    // someVal is not in array "n"
}
soapergem
  • 9,263
  • 18
  • 96
  • 152
0
    var n = new Array(),num;
function TableOn()
{
    document.write("<table border='1'>");
}
function TableOff()
{
    document.write("</table>");
}
function check_repition()
{
num=Math.round((1+(Math.random()*40)))
if(n.indexOf(num)==-1)
return true;
else 
return false;
}

 function RandNum()
    {

        for(var i=0;i<7;i++)
        {
if(check_repition())
            n[i] =num;
else // keep checking
{
    check_repition()
     n[i] =num;
}
        }
        TableOn();
        for(var c=0;c<7;c=c+1)
        {
            document.write("<tr><td>"+n[c]+"</td></tr>");
        }
        TableOff();
    }
    RandNum()
ProllyGeek
  • 15,517
  • 9
  • 53
  • 72
0

I'd use a string, storing the generated random numbers with a divider. Then check if the newly generated number is in that string.

Something like this

generated = "";
for(var i=0;i<7;i++)
{
    generate = Math.round((1+(Math.random()*40))); //generate = 5
    while (generated.indexOf("[" + generate + "]") != -1) { //checking if the [5] is already in the generated string, and loop until it's a different number
        generate = Math.round((1+(Math.random()*40))); //get a new random number
    }
    generated += "[" + generate + "]";
    n[i] = generate;
}

or you can take another longer approach

for(var i=0;i<7;i++)
{
    repeated = true;
    while (repeated) { 
        repeated = false;
        generate = Math.round((1+(Math.random()*40)));
        for (var a=0; a < i, a++) {
            if (generate == n[a]) { repeated = true; }
        }
    }
    n[i] = generate;
}
Aister
  • 359
  • 1
  • 6
0

Not sure if OP's requirement of non-repeating is really needed, but here's a fiddle of something that could work if your number range isn't too big:

http://jsfiddle.net/6rEDV/1/

function range(start, end, step) {
    if (typeof step === 'undefined') {
        step = 1;
    }

    if (typeof start === 'undefined' || typeof end === 'undefined') {
        throw TypeError('Must have start and end');
    }

    var ret = [];
    for (var i = start; i <= end; i += step) {
        ret.push(i);
    }

    return ret;
};

// source: http://stackoverflow.com/a/6274381/520857
function shuffle(o) { //v1.0
    for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
};

function getNonRepeatingRand(min, max, num) {
    var arr = shuffle(range(min, max));
    return arr.slice(0, num-1);
}

// Get 7 random numbers between and including 1 and 1000 that will *not* repeat
console.log(getNonRepeatingRand(1,1000,7));

A possibly slower, but less memory intensive method:

http://jsfiddle.net/Qnd8Q/

function rand(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function getNonRepeatingRand(min, max, num) {
    var ret = [];

    for (var i = 0; i < num; i++) {
        var n = rand(min, max);
        if (ret.indexOf(n) == -1) {
            ret.push(n);
        } else {
            i--;
        }
    }
    return ret;
}

console.log(getNonRepeatingRand(1,5,5));
Populus
  • 7,470
  • 3
  • 38
  • 54
0

Here's a function to generate an array of n unrepeated random numbers in [min, max):

function rands(n, min, max) {
  var range = max - min;
  if (range < n)
    throw new RangeError("Specified number range smaller than count requested");

  function shuffle() {
    var deck = [], p, t;
    for (var i = 0; i < range; ++i)
      deck[i] = i + min;

    for (i = range - 1; i > 0; --i) {
      p = Math.floor(Math.random() * i);
      t = deck[i];
      deck[i] = deck[p];
      deck[p] = t;
    }
    return deck.slice(0, n);
  }

  function find() {
    var used = {}, rv = [], r;
    while (rv.length < n) {
      r = Math.floor(Math.random() * range + min);
      if (!used[r]) {
        used[r] = true;
        rv.push(r);
      }
    }
    return rv;
  }

  return range < 3 * n ? shuffle() : find();
}

This code checks the range of possible values and compares it to the number of random values requested. If the range is less than three times the number of values requested, the code uses the shuffle to avoid the terrible performance of the lookup approach. If the range is large, however, the lookup approach is used instead.

Pointy
  • 405,095
  • 59
  • 585
  • 614