Home > Software design >  Constantly generating unique and random values in a specific range in C#
Constantly generating unique and random values in a specific range in C#

Time:03-16

I am implementing this code in my discord bot, where I want to be able to generate unique numbers from 1 to 10 (as suggested above) whenever I input a single command.

Turns out that the values sometimes are repeated. Therefore I was suggested to add an array (used[ ]) and a loop in order to check every time if the value has been generated already.

Random random = new Random();
    int[] used = new int[10];
    int rng = 0;
    while (!used.Contains(rng))
    {
        rng = random.Next(1, 10);
    }

    /* 
    I wish to store the generated value "rng" to the "used" array.
    e.g.
    used[0] = rng
    used[1] = rng
    used[2] = rng
    etc.
    */
    Console.WriteLine("The number generated is "   Convert.ToString(rng));

However, I don't know how to constantly add values to an array in an arranged order. (as seen by the commentations above)

In a more simple way, For 10 times I want the system to generate a number, and those numbers are randomly picked out of [1,10] and only once. If all the numbers have been generated once, all are free to be generated again.

Sorry for my bad interpretation. I have refined it with the comments that everyone has contributed.

CodePudding user response:

Here is a solution, that shuffles the values and returns each value until the list is exhausted, then starts all over:

int[] GenerateNewArray()
{
    // Define the values we wish to return
    int[] baseValues = new []{1,2,3,4,5,6,7,8,9,10};
    Random rnd=new Random();
    // Shuffle the array randomly using Linq
    return baseValues.OrderBy(x => rnd.Next()).ToArray(); 
}

void Main()
{
    while (true)
    {
        // Generate a new randomized array
        var values = GenerateNewArray();
        // Print each value 
        for (int i=0;i<10;i  )
        {
            Console.WriteLine($"The number generated is {values[i]}");
        }
    }
}

CodePudding user response:

Rather than storing in an array, looking for duplicates etc., just use a HashSet This only accepts unique values, and if you try to add a duplicate it will be simply ignored.

Or you can just do a check to see if it exists

HashSet<int> integerSet = new HashSet<int>();

if (hashSet.Contains(rng ))
  // element already exists in set
else 
   //Doesn't exist

Of course, if you just keep generating each number randomly until you have generated everything in the range, then you might as well just simply generate an array/list of elements with every number and save yourself processing time!

CodePudding user response:

Using a list is a good way to start, but before continuing the comment go check out the list documentation

In small talk a list is an IEnumerable of a type you choose, in your case to declare and instanciate a list you should write like this List<int> listName = new List<int>(); and the main difference between an array and a list is that you can populate the list whenever you want without the length declaration, to do that you can add listName.Add(2); (2 : the integer value that you want to add) or remove values listName.Remove(0) (0 : the position of the list that need to be removed, ex: 0 is the first value inside the list because position 0 is the start)

Random random = new Random();
List<int> listName = new List<int>();
int rng = 0, counterOfValues = 0;

while (counterOfValues < 10)
{
    rng = random.Next(1, 10);

    If(!listName.Contains(rng))
    {
        listName.Add(rng);
        Console.WriteLine("The number generated is "   listName.Last().ToString());
        
        If(counterOfValues < 10)
        {
            counterOfValues  ;
        }
        else
        {
            counterOfValues = 0;
        }
    }
}

This should probably do the work ("should" because it's some code I wrote out of my head, so sorry about caps ecc) Let me know if it works as intended or we need to correct something!

P.S: If you want the user to select the range of the randomic values just change the value of counterOfValues in the lowest value and the 10's with the higher value

CodePudding user response:

Using a HashSet is better to know the numbers that you are use. But in your case, I think it's better use a List and remove elements:

var list = new List<int>();
for (int i = 1; i <= 10; i  )
   list.Add(i);

// List is 0-index
// list = 1 2 3 4 5 6 7 8 9 10
int rng = random.Next(0, list.Count - 1);
// Suppose rgn=3: You get 3 value and remove it from the list
var value = list[rgn];
list.RemoveAt(rgn);

// list = 1 2 4 5 6 7 8 9 10
// Now you get a value between 0...8 (list.Count is 9)
rng = random.Next(0, list.Count - 1);
// Suppose rgn=3: You get 4 value and remove it from the list
var value = list[rgn];
list.RemoveAt(rgn);

// list = 1 2 5 6 7 8 9 10
// Now you get a value between 0...7 (list.Count is 8)
rng = random.Next(0, list.Count - 1);
// Suppose rgn=5: You get 7 value and remove it from the list
var value = list[rgn];
list.RemoveAt(rgn);

// list = 1 2 5 6 8 9 10
...

When list has one element you don't need use random. When your list is empty, fill again and repeat the whole process.

In this form you always get an element with each random call. Using HashSet you may try a lot of random calls to get a nonused number.

A class for that maybe:

public class RandomClass
{
   private readonly List<int> _list;

   private readonly Random _random;

   public RandomClass()
   {
      this._list = new List<int>();
      this._random = new Random();
   }

   private void PopulateList()
   {      
      for (int i = 1; i <= 10; i  )
         this._list.Add(i);
   }

   public int GetNumber()
   {
      if (this._list.Count == 0)
      {
         this.PopulateList();
      }

      if (this._list.Count > 1)
      {
         int rng = this._random.Next(0, this._list.Count);
         var value = this._list[rgn];
         this._list.RemoveAt(rgn);
         return value;
      }
      else
      {
         var value = this._list[0];
         this._list.RemoveAt(0);
         return value;
      }
   }
}
  • Related