Padgey85
Padgey85

Reputation: 209

Random number generator with no duplicates

Basically I'm creating a program to randomly generate 6 unique lottery numbers so there is no duplicates in the same line, here is the code I have so far...

        //Generate 6 random numbers using the randomiser object

        int randomNumber1 = random.Next(1, 49);
        int randomNumber2 = random.Next(1, 49);
        int randomNumber3 = random.Next(1, 49);
        int randomNumber4 = random.Next(1, 49);
        int randomNumber5 = random.Next(1, 49);
        int randomNumber6 = random.Next(1, 49);

        textBox1.Text = randomNumber1.ToString();
        textBox2.Text = randomNumber2.ToString();
        textBox3.Text = randomNumber3.ToString();
        textBox4.Text = randomNumber4.ToString();
        textBox5.Text = randomNumber5.ToString();
        textBox6.Text = randomNumber6.ToString();

    }

I'm getting random numbers but sometimes there is the same number on the same line, how do I make each number unique????

Thanks in advance

Upvotes: 18

Views: 92633

Answers (12)

Ashish Sinha
Ashish Sinha

Reputation: 180

It's too late but I use a Method named M_Randomizer created by me. It may look as too much work, but it's technique is different from traditional which is based on generating a random number and checking the previously generated list for uniqueness. This code while generating a new random number, never looks for the previously generated. And if we talk about touching all combinations, I have tested this method till 9 factorial, maybe little bias for some but it touches all.

using System;
class Randomizer
{
public int[] M_Randomizer(int x)
{
    bool b = false;
    if (x < -1)
    {
        b = true;
        x = -1 * x;
    }
    if(x == -1)
        x = 0;
    if (x < 2)
        return new int[x];

    int[] site;
    int k = new Random(Guid.NewGuid().GetHashCode()).Next() % 2;
    if (x == 2)
    {
        site = new int[2];
        site[0] = k;
        site[1] = 1 - site[0];
        return site;
    }
    else if (x == 3)
    {
        site = new int[3];
        site[0] = new Random(Guid.NewGuid().GetHashCode()).Next(0, 3);
        site[1] = (site[0] + k + 1) % 3;
        site[2] = 3 - (site[0] + site[1]);
        return site;
    }
    site = new int[x];
    int a = 0, m = 0, n = 0, tmp = 0;
    int[] p = M_Randomizer(3);
    int[] q;

    if (x % 3 == 0)
        q = M_Randomizer(x / 3);
    else
        q = M_Randomizer((x / 3) + 1);
    if (k == 0)
    {
        for (m = 0; m < q.Length; m++)
        {
            for (n = 0; n < p.Length && a < x; n++)
            {
                tmp = (q[m] * 3) + p[n];
                if (tmp < x)
                {
                    site[a] = tmp;
                    a++;
                }
            }
        }
    }
    else
    {
        while (n < p.Length)
        {
            while (a < x)
            {
                tmp = (q[m] * 3) + p[n];
                if (tmp < x)
                {
                    site[a] = tmp;
                    a++;
                }
                m = m + k;
                if (m >= q.Length)
                    break;
            }
            m = m % q.Length;
            n++;
        }
    }

    a = (new Random(Guid.NewGuid().GetHashCode()).Next() % 2) + 1;
    k = new Random(Guid.NewGuid().GetHashCode()).Next() % 10;
    if (k > 5)
        for (int i = a; i < k; i++)
            while (a < site.Length)
            {
                if (k % (a + 1) == 0)
                {
                    tmp = site[a - 1];
                    site[a - 1] = site[a];
                    site[a] = tmp;
                }
                a = a + 2;
            }

    k = new Random(Guid.NewGuid().GetHashCode()).Next() % 10;
    if (k > 5)
    {
        n = x / 2;
        k = 0;
        if (x % 2 != 0)
            k = (new Random(Guid.NewGuid().GetHashCode()).Next() % 2);

        p = new int[n + k];
        m = (x - n) - k;
        for (a = 0; m < x; a++, m++)
            p[a] = site[m];

        m = n + k;
        for (a = (x - m) - 1; a >= 0; a--, m++)
            site[m] = site[a];

        for (a = 0; a < p.Length; a++)
            site[a] = p[a];
    }

    int[] site2;
    int[] site3 = new int[x];
    if (b)
        return site;
    else
        site2 = M_Randomizer(-1 * x);

    for (a = 0; a < site.Length; a++)
        site3[site2[a]] = site[a];

    return site3;
}

public int[] M_Randomizer(int x, int start)
{
    int[] dm = M_Randomizer(x);

    for(int a = 0; a < x; a++)
        dm[a] = dm[a] + start;

    return dm;
}
}

Upvotes: 1

Pierre
Pierre

Reputation: 9052

Here is a small program using recursion to generate number lines, and also uses recursion to randomize and get unique numbers.

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static Random random;
    public static List<int> lottoNumbers = Enumerable.Range(1, 49).ToList();
    public static void Main()
    {
        random = new Random((int)DateTime.Now.Ticks);

        var LinesToGenerate = 10;

        GenerateNumbers(LinesToGenerate);
    }

    public static void GenerateNumbers(int LineCount)
    {
        int[] SelectedNumbers = new int[6];
        for (var i = 0; i < 6; i++)
        {
            var number = GetRandomNumber(lottoNumbers.ToArray());

            while (SelectedNumbers.Contains(number))
                number = GetRandomNumber(lottoNumbers.ToArray());

            SelectedNumbers[i] = number;
        }

        var numbersOrdered = SelectedNumbers.OrderBy(n => n).Select(n => n.ToString().PadLeft(2, '0'));
        Console.WriteLine(string.Join(" ", numbersOrdered));

        if (LineCount > 1)
            GenerateNumbers(--LineCount);
    }

    //Recursively and randomly removes numbers from the array until only one is left, and returns it
    public static int GetRandomNumber(int[] arr)
    {
        if (arr.Length > 1)
        {
            //Remove random number from array
            var r = random.Next(0, arr.Length);
            var list = arr.ToList();
            list.RemoveAt(r);
            return GetRandomNumber(list.ToArray());
        }

        return arr[0];
    }
}

Upvotes: 0

tieubavuong
tieubavuong

Reputation: 11

It's my solution: generate array of number

/// <summary>
/// auto generate a array with number element and max value is max
/// </summary>
/// <param name="number">number element of array</param>
/// <param name="max">max value of array</param>
/// <returns>array of number</returns>
public static int[] createRandomArray(int number, int max)
{
    List<int> ValueNumber = new List<int>();
    for (int i = 0; i < max; i++)
        ValueNumber.Add(i);
    int[] arr = new int[number];
    int count = 0;
    while (count < number)
    {
        Random rd = new Random();
        int index = rd.Next(0,ValueNumber.Count -1);
        int auto = ValueNumber[index];
        arr[count] = auto;
        ValueNumber.RemoveAt(index);
        count += 1;
    }
    return arr;
}

Upvotes: 1

Fernando Ortu
Fernando Ortu

Reputation: 99

   List<int> aux = new List<int>();
   while(aux.Count < 6)
   {
      int rnd = random.Next(1,49);
      if(!aux.Contains(rnd))aux.add(rnd);
   } 

if you put all Texbox in the same panel you can do that

  int j = 0;
  foreach(Control x in MyPanel.Controls)
  {
     if(x is TexBox)
     {
        x.Text = aux[j].toString();
        j++;
     } 
  } 

Upvotes: 2

Sean Dawson
Sean Dawson

Reputation: 5786

A functional approach could be to generate an infinite sequence of random numbers, filter out non-unique numbers and take the number of unique numbers you need.

For example:

private IEnumerable<int> RandomDigitStream(int seed)
{
    Random random = new Random(seed);
    while (true)
    {
        yield return random.Next(DIGIT_MIN, DIGIT_MAX);
    }
}

private List<int> GenerateUniqueRandomNumbers(int seed, int count)
{
     // Assert that DIGIT_MAX - DIGIT_MIN > count to ensure
     // algorithm can finish

     return RandomDigitStream(seed)
        .Distinct()
        .Take(count)
        .ToList();
}

The efficiency of this algorithm is mainly dependent on how Distinct is implemented by the .NET team. Its memory usage would grow with the number of digits you require and the range of digits produced by the random function. It also has an unpredictable running time as it depends on the probability distribution of the random function. In fact it is possible for this algorithm to get stuck in an infinite loop if the range of digits produced by the random algorithm is less than the number of digits you require.

Looking at it practically however, it should be fine for a small amount of digits but if you are looking at a large number (100 +) you might want to look at other methods.

It would be more efficient to craft a random algorithm that only produces unique numbers in the first place if that is even possible without using a lookup table.

Upvotes: 0

Daniel Romeo
Daniel Romeo

Reputation: 1

Yes. Use array. Loop how many times you want: Generate a random number, Loop through array and compare all with the generated number. If there's a match then loop again till there's no match. Then store it.

Done:)

Upvotes: -3

Timothy Shields
Timothy Shields

Reputation: 79441

Using this extension method for reservoir sampling:

public static IList<T> TakeRandom<T>(
    this IEnumerable<T> source, int count, Random random)
{
    var list = new List<T>(count);
    int n = 1;
    foreach (var item in source)
    {
        if (list.Count < count)
        {
            list.Add(item);
        }
        else
        {
            int j = random.Next(n);
            if (j < count)
            {
                list[j] = item;
            }
        }
        n++;
    }
    return list;
}

You can sample your collection like this:

var random = new Random();
var numbers = Enumerable.Range(1, 49).TakeRandom(6, random);
numbers.Shuffle(random);

Note the returned numbers will be uniformly sampled out of all (49 choose 6) possibilities for a set of 6 numbers out of {1, 2, ..., 49}, but they will neither remain in order nor be uniformly shuffled. If you want to have the order randomized as well, you can easily do a standard Fisher-Yates shuffle afterwards.

public static void Shuffle<T>(this IList<T> list, Random random)
{
    for (int i = 0; i < list.Count; i++)
    {
        int j = random.Next(i, list.Count);
        T temp = list[j];
        list[j] = list[i];
        list[i] = temp;
    }
}

Note a more heavily optimized version of Fisher-Yates shuffle can be found in this answer: Randomize a List<T>

Upvotes: 3

Umut D.
Umut D.

Reputation: 1846

It's so easy with array and OOP (Object Oriented Programming). Before you start you have to add Linq (using System.Linq) library to your project.

Random random = new Random();
int[] array = new int[6];
int number;

for (int i = 0; i < 6; i++)
{
    number = random.Next(1, 50);
    if (!array.Contains(number)) //If it's not contains, add number to array;
    array[i] = number;
    else //If it contains, restart random process
    i--;
}

for (int i = 1; i < 7; i++)
{
    foreach (Control c in this.Controls) //Add random numbers to all Textboxes
    {
        if (c is TextBox && c.Name.EndsWith(i.ToString()))
        {
            c.Text = array[i - 1].ToString();
        }
    }
}

Upvotes: 0

Bathsheba
Bathsheba

Reputation: 234635

Returning repeat values is a necessity in order for a generator to satisfy a necessary statistical property of randomness: the probability of drawing a number is not dependent on the previous numbers drawn.

You could shuffle the integers in the range 1 to 49 and return the first 6 elements. See http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle for more details on such a shuffler.

However, I think you get a slight statistical bias by doing this.

The best way is probably to use random.Next(1, 49); and reject any repeat. That will be free from statistical bias and the fact that you're only wanting 6 from 49 possibilities, the number of collisions will not slow the algorithm appreciably.

Upvotes: 6

James Cronen
James Cronen

Reputation: 5763

You can't. You've only specified that each number be a random number from 1 to 49, not that it shouldn't match any duplicates.

Since you've got a relatively small set of numbers, your best bet is probably to draw the random numbers, put them into a HashSet, then if you need more, pull more. Something like this:

HashSet<int> numbers = new HashSet<int>();
while (numbers.Count < 6) {
    numbers.Add(random.Next(1, 49));
}

Here you're taking advantage of the HashSet's elimination of duplicates. This won't work with a List or other collection.

Upvotes: 14

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101681

You need to store them in a collection and each time you pick a new number you need to make sure it's not present already, otherwise you need to generate a new number until you find a unique number.

Instead of this, I would generate a sequence between 1 and 49, shuffle them and pick 6 number out of the sequence, for example:

var rnd = new Random();
var randomNumbers = Enumerable.Range(1,49).OrderBy(x => rnd.Next()).Take(6).ToList();

Upvotes: 40

Mawg
Mawg

Reputation: 40140

Look at using an array to hold your 6 numbers.

Each time you generate one, loop through the array to make sure it is not already there. If it is, then generate another & loop again until you have a non-match.

Upvotes: 0

Related Questions