Home > Back-end >  Fill 2d array with unique random numbers from 0 to 15 C#
Fill 2d array with unique random numbers from 0 to 15 C#

Time:10-06

I can't fill it with numbers to 0 - 15 then shuffle the array, so that's not the solution

I used this code in C but now in c# it doesn't work, for some reason this code let some numbers pass the do while.

Random r = new Random();
        bool unique;
        int rand_num;

        for (int i = 0; i < 4; i  )
        {
            for (int j = 0; j < 4; j  )
            {
                do
                {
                    unique = true;
                    rand_num = r.Next(16);
                    for (int k = 0; k < 4; k  )
                    {
                        for (int l = 0; l < 4; l  )
                        {
                            if (numbers[k, j] == rand_num)
                            {
                                unique = false;
                            }
                        }
                    }

                } while (!unique);
                
                numbers[i, j] = rand_num;
            }
        }


    }

CodePudding user response:

If the list of possible numbers is small, as in this case, just create the full list and randomise it first, then take the items in the order they appear. In your case, you can put the randomised numbers into a queue, then dequeue as required.

var r = new Random();
var numberQueue = new Queue<int>(Enumerable.Range(0, 16).OrderBy(n => r.NextDouble()));
var numbers = new int[4, 4];

for (var i = 0; i <= numbers.GetUpperBound(0); i  )
{
    for (var j = 0; j <= numbers.GetUpperBound(1); j  )
    {
        numbers[i, j] = numberQueue.Dequeue();
    }
}

CodePudding user response:

The approach you have taken may end up in continuous looping and take lot of time to complete.

Also checking for value in 2D using nested for loop is not efficient.

You can use HashSet to keep track of unique value. Searching in HashSet is fast.

following is the code approach I suggest.

var hashSet = new HashSet<int>();
var r = new Random();
var arr = new int[4, 4];
for(var i = 0;i<4;i  )
{
    for(var j = 0;j<4;j  )
    {
        // Generate random value between 0 and 16.
        var v = r.Next(0, 16);
        // Check if the hashSet has the newly generated random value.   
        while(hashSet.Contains(v))
        {
            // generate new random value if the hashSet has the earlier generated value.
            v = r.Next(0, 16);
        }
        //Add value to the hashSet.
        hashSet.Add(v);
        // add value to the 2D array.
        arr[i, j] = v;
    }
}

I hope this will help solving your issue.

CodePudding user response:

The problem with your current approach is that as you get closer to the end of the array, you have to work harder and harder to get the next random value.

Imagine you roll a die, and each time you want to get a unique value. The first time you roll, any result will be unique. The next time, you have a 1/6 chance of getting a number that has already been obtained. And then a 2/6 chance, etc. and in the end most of your rolls will be non-unique.

In your example, you have 16 places that you want to fill with numbers 0 to 15. This is not a case of randomly generating numbers, but randomly placing them. How do we do this with a deck of cards? We shufle them!

My proposal is that you fill the array with unique sequential values and then shuffle them:

Random random = new Random();
int dim1 = array.GetLength(0);
int dim2 = array.GetLength(1);
int length = dim1 * dim2;

for (int i = 0; i < length;   i)
{
    int x = i / dim1;
    int y = i % dim1;
    array[x, y] = i; // set the initial values for each cell
}

// shuffle the values randomly
for (int i = 0; i < length;   i)
{
    int x1 = i / dim1;
    int y1 = i % dim1;

    int randPos = random.Next(i, length);
    int x2 = randPos / dim1;
    int y2 = randPos % dim1;

    int tmp = array[x1, y1];
    array[x1, y1] = array[x2, y2];
    array[x2, y2] = tmp;
}

The shuffle in this code is based on the shuffle found here

CodePudding user response:

I suggest you to use the Fisher-Yates algorithm to generate your non-repeatable sequence of random numbers.

It would be very straight-forward to implement a code to fill in a 2d array with those numbers, then.

List<int> seq = Enumerable.Range(0,16).ToList();
int[,] numbers = new int[4,4];
Random r = new();
for (int i = 0; i < 4; i  ) {
  for (int j = 0; j < 4; j  ) {
    int n = r.Next(0, seq.Count);
    numbers[i,j] = seq[n];
    seq.RemoveAt(n);
  }
}

CodePudding user response:

            int[,] numbers = new int[4, 4];
            Random r = new Random();
            bool unique;
            int rand_num;
            List<int> listRandom = new List<int> { };

            for ( int i = 0; i < 4; i   )
            {
                for ( int j = 0; j < 4; j   )
                {
                    do
                    {
                        unique = false;
                        
                        if (!listRandom.Contains( rand_num = r.Next( 0, 16 )))
                        {
                            listRandom.Add( rand_num );
                            numbers[i, j] = rand_num;
                            unique = true;
                        }

                    } while ( !unique );
                }
            }
  • Related