19

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

Padgey85
  • 211
  • 1
  • 2
  • 7
  • 5
    One approach is to shuffle the numbers (Fisher-Yates) and then take the first 6. Another approach is to reject already encountered numbers via a hashset. – CodesInChaos Nov 14 '14 at 13:54
  • Possible duplicate http://stackoverflow.com/questions/22737687/how-to-create-an-array-of-non-repeating-random-numbers – gpullen Nov 14 '14 at 13:54
  • 4
    Don't forget that allowing no duplicates makes the numbers less random. – IS4 Nov 14 '14 at 14:26
  • 2
    Yet another approach is to use [reservoir sampling](http://en.wikipedia.org/wiki/Reservoir_sampling) as I show in my answer. It might be overkill for such a small problem, but if you ever want to pick, for example, 6 numbers out of 100000 with no duplicates, it's probably better to go the reservoir sampling route than to create a list with that many items and sort it. – Timothy Shields Nov 14 '14 at 18:33
  • Check my answer here: https://stackoverflow.com/a/47420924/700693 – Evren Ozturk Nov 21 '17 at 19:17

12 Answers12

39

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();
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
14

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.

James Cronen
  • 5,715
  • 2
  • 32
  • 52
  • 2
    Good point. Got stuck in the trap to think about creating six numbers, THEN determine if duplicates need to be resolved. Thanks. – James Cronen Nov 14 '14 at 13:57
  • 1
    Just as a note - in this particular situation you might just as well use `SortedSet` which will give you your numbers in sorted order out-of-the-box. On the other hand any proper `ISet` implementation should be sufficient, so it is not necessary to use `HashSet` (but it's still Ok). – Grx70 Nov 14 '14 at 14:01
6

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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 2
    [And the canonical shuffle here on StackOverflow.](http://stackoverflow.com/questions/273313/randomize-a-listt-in-c-sharp/1262619#1262619) – Matthew Watson Nov 14 '14 at 13:56
3

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>

Community
  • 1
  • 1
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
2
   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++;
     } 
  } 
1

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;
}
dpr
  • 10,591
  • 3
  • 41
  • 71
1

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;
}
}
Ashish Sinha
  • 87
  • 2
  • 10
0

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.

Mawg says reinstate Monica
  • 38,334
  • 103
  • 306
  • 551
  • 1
    good idea, but you should show people a code example based on the question with code and that would really help people... – Tom Stickel Feb 08 '17 at 16:48
  • Someone just downvoted this (not you, your comment was one year ago yesterday, by coincidence), so I will just say that we are not a code writing service. Really, people should post code, tell us what it should do and what it actually is doing and we can help to reconcile the latter two. If we give them code, we do not help them. Even this, giving an (extremely basic) algorithm is pushing it a bit; but, if he can figure out how to code this, then will at least have learned something. – Mawg says reinstate Monica Feb 09 '18 at 12:41
0

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();
        }
    }
}
Umut D.
  • 1,746
  • 23
  • 24
0

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.

Sean Dawson
  • 5,587
  • 2
  • 27
  • 34
0

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];
    }
}
Pierre
  • 8,397
  • 4
  • 64
  • 80
-3

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:)