-1

I'm currently trying to create a program that generates random numbers between 1 and 45 with no duplicates. My program works when I run it without the else statement whenever a duplicate comes up it inputs the number 0, when I use the else statement the function breaks. I want to display random numbers between 1 and 45 however the variable size must dictate the size of the array. For example random integers between 1 and 45 with an array size of 35.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RandomArray
{
public class RandomArrayNoDuplicates
{
    static void Main(string[] args)
    {
        int size = 45;
        int[] noDuplicateArray = new int[size];
        noDuplicateArray = InitializeArrayWithNoDuplicates(size);
        DisplayArray(noDuplicateArray);
        ExitProgram();

    } //end Main
    static Random rng = new Random();

    /// <summary>
    /// Creates an array with each element a unique integer
    /// between 1 and 45 inclusively.
    /// </summary>
    /// <param name="size"> length of the returned array < 45
    /// </param>
    /// <returns>an array of length "size" and each element is
    /// a unique integer between 1 and 45 inclusive </returns>
    ///
    static void ExitProgram()
    {
        Console.Write("\n\nPress any key to exit program: ");
        Console.ReadKey();
    }//end ExitProgram

    public static int[] InitializeArrayWithNoDuplicates(int size)
    {
    int number;
    int[] noDuplicates = new int[size];

        for (int i = 0; i < size; i++)
        {
            number = rng.Next(1, size);
            if (!noDuplicates.Contains(number))
                noDuplicates[i] = number;
           // else
           //     i--;
        }
        return noDuplicates;

    }
    static void DisplayArray(int[] noDuplicates)
    {
    foreach (int element in noDuplicates)
        {
            Console.Write("\t" + element + "\n");
        }
    }
}
}

The issue lies in this bit of code:

public static int[] InitializeArrayWithNoDuplicates(int size)
    {
    int number;
    int[] noDuplicates = new int[size];

        for (int i = 0; i < size; i++)
        {
            number = rng.Next(1, size);
            if (!noDuplicates.Contains(number))
                noDuplicates[i] = number;
           // else
           //     i--;
        }
        return noDuplicates;

but I'm unsure how to fix it. I would prefer to use the random.next function rather than using enumberable approach. Thanks

2 Answers2

2

Try following :

        public static int[] InitializeArrayWithNoDuplicates(int size)
        {
            Random rand = new Random();
            return Enumerable.Repeat<int>(0, size).Select((x, i) => new { i = i, rand = rand.Next() }).OrderBy(x => x.rand).Select(x => x.i).ToArray();
        }

The code creates an array of integers equal to size (Enumerable.Repeat(0, size)) filled with the value zero just to get an array equal to size. So the select creates a two dimensional array where i is the numbers 0 to size and rand is a random number. i doesn't repeat. The code then simply orders two dimensional array by the random number and then extracts the i values only.

jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Nice answer. Can you break down what `return Enumerable.Repeat(0, size).Select((x, i) => new { i = i, rand = rand.Next() }).OrderBy(x => x.rand).Select(x => x.i).ToArray();` is doing please? – S A Aug 27 '17 at 13:54
  • 1
    Add explanation in the answer. – jdweng Aug 27 '17 at 13:58
  • This works if I want any number between 1 and 45. However I want it to consistently be random integers between 1 and 45 with the size of the array varying. – Khargan Powell Aug 28 '17 at 02:18
  • You would need to variables One indicating the range of random variables and the other for the number of variables you need. The code would be the same except you would add a Take() method indicating how many numbers you want.. – jdweng Aug 28 '17 at 07:15
  • One weakness here is the use of a new instance of `Random` each time the function `InitializeArrayWithNoDuplicates` is called. This would lead to crippling bias. – David Heffernan Aug 28 '17 at 09:21
  • It is not a weakness.There is no bias calling the constructor each time the function is called since the DateTime is used to initialize the random number generator.The seed is random enough not to cause any bias. My probability teacher always asked the question if you had a perfectly random deck of cards.Then shuffled.Do you get a deck that is more or less random.The answer is really the same.So in this case you have a random number generator and randomize it more times (calling the constructor) you do not get numbers less random. – jdweng Aug 28 '17 at 09:51
  • @jdweng It's pretty simple to write a test program to demonstrate that is not the case. In fact you don't really need a test program, it's just obvious. Consecutive calls to the `Random` constructor are liable to have identical seeds. The documentation spells this out rather clearly. – David Heffernan Aug 28 '17 at 10:29
  • *The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a single Random object to generate all random numbers. You can also work around it by modifying the seed value returned by the system clock and then explicitly providing this new seed value to the Random(Int32) constructor.* – David Heffernan Aug 28 '17 at 10:29
  • Identical seeds only occur if you call the random generator constructor twice within a very short period of time. You were not originally refereeing to this situation. By adding a 1 second wait between calls solves this issue if it is actually occurring. You original response was a bias which is something completely different. – jdweng Aug 28 '17 at 10:42
  • Adding a 1 second wait is not practical at all. The simple solution is to use a single PRNG instance, perhaps supplied as an argument. Calling your `InitializeArrayWithNoDuplicates` function twice in succession, and creating two PRNG instances with the same seed leads to bias. – David Heffernan Aug 28 '17 at 10:56
0

if you go to Next method's definition you will see

// Exceptions:
//   T:System.ArgumentOutOfRangeException:
//     minValue is greater than maxValue.

and

rng.Next(1, 0);

raise ArgumentOutOfRangeException exception

Numan KIZILIRMAK
  • 555
  • 4
  • 20