Generating and storing unique and random numbers within a range - c#

I tried the following code to generate random numbers and store them in a HashSet in c#:
class program
{
static void Main(String[] args)
{
Random r=new Random();
HashSet <int> h = new HashSet<int>();
for (int j=0;j<9;++j)
{
h.Add(r.Next(9));
}
int [] array = h.ToArray();
foreach(int i in array)
Console.WriteLine(i);
Console.ReadLine();
}
}
Each time I execute the program, the number of elements being displayed differs. Since I'm using a loop to store 9 values, I expect 9 values to be displayed, which is not happening. What could be the possible error?

HashSet doesn't contain duplicates.Your loop runs 9 times but only unique numbers are added to the HashSet.Add your numbers directly to your array and you should see 9 numbers displaying. Or use a wider range to generate random numbers.Btw you can verify that how many numbers in the HashSet like this, after the for loop:
Console.WriteLine(h.Count);
Alternatively you can change your for loop like this:
for (int j = 0; j < 9; ++j)
{
if(!h.Add(r.Next(9))) j--;
}

Related

change values in arrays until all values are different

i am trying to generate 5 random numbers in an array and output them, however i don't want 2 values to be the same, what do i need to add to this code to prevent this?
using System;
public class Program
{
public static void Main()
{
int count = 0;
int Randomnum=0;
int[] num = new int[5];
Random r = new Random();
while(count < 5){
Randomnum= r.Next(1,10);
num[count]=Randomnum;
count = count+ 1;
}
foreach(var entry in num)
{
Console.WriteLine(entry);
}
}
}
You could get your full set using Enumerable.Range, order them by a random value and get top 5. ie:
var numberSet = Enumerable.Range(1,10);
var randomSet = numberSet.OrderBy(s => Guid.NewGuid()).Take(5);
foreach (var entry in randomSet)
{
Console.WriteLine(entry);
}
Your current implementation could be edited so that it adds the new random value (and increments the counter) only if num does not already contain the value.
Your variables are defined as follows:
int count = 0;
int randomNum = 0;
int[] num = new int[5];
Random r = new Random();
One way of checking whether or not num contains the new value is by using Array.IndexOf(). This method returns the index at which the value you provide is found in the array that you provide. If the value you provide is not found in the array, the method will return -1.
(Note: Array.IndexOf() specifically returns the lower bound of the array minus 1 when no match is found. Seeing as you populate num starting at index 0, the return value is therefore -1 in your scenario. More about the computation of an array's lower bound here).
The implementation of your while loop could thus be adjusted to:
while (count < 5)
{
randomNum = r.Next(1, 10);
if (Array.IndexOf(num, randomNum) < 0)
{
num[count] = randomNum;
count += 1;
}
}
An alternative to using Array.IndexOf() is to use Enumerable.Contains() from the System.Linq namespace. I find it to be more readable, so I just thought I'd mention it.
//using System.Linq;
while (count < 5)
{
randomNum = r.Next(1, 10);
if (!num.Contains(randomNum))
{
num[count] = randomNum;
count += 1;
}
}
That being said, you may want to consider using a HashSet rather than an array for this scenario. A HashSet can only contain distinct values, which is what you want to achieve.
HashSet's .Add() method actually checks whether your HashSet already contains the value you are trying to add. If it does, the value will not be added again.
Due to this behavior, you can call .Add() for every random value that you generate, without manually having to check for existence beforehand.
Another beneficial side effect of this is that your count and randomNum variables are no longer necessary.
Using a HashSet rather than an array, your code (prior to the code that prints the result to the console) could be implemented as follows:
//using System.Collections.Generic;
HashSet<int> num = new();
Random r = new Random();
while (num.Count < 5)
{
num.Add(r.Next(1, 10));
}
Example fiddle with all three implementations here.

Is there a way to add a number of elements to the array in C#?

I'm learning C# and I have created a code to add random numbers to a List using a for loop.
class Program
{
static void Main(string[] args)
{
Random numberGen = new Random();
List<int> randomNum = new List<int>();
for (int i = 0; i < 10; i++)
{
randomNum.Add(numberGen.Next(1, 100));
}
for (int i = 0; i < randomNum.Count; i++)
{
Console.WriteLine(randomNum[i]);
}
Console.ReadKey();
}
}
I want to know if there is a way to add random numbers to an array with a similar method?
The size of an array is fixed at the time of creation, so you can't add to an array; you can, however: create a new array that is bigger, copy the old data, and then append the new value(s) - Array.Resize does the first two steps - but: this is pretty expensive, which is why you usually use a List<T> or similar for this scenario. A List<T> maintains an oversized array in the background, so that it only has to resize and copy the underlying array occasionally (essentially, it doubles the size every time it gets full, so you get something approximating O(Log2(N)) overhead due to growth).
You could just assign to the relevant index directly, but note you'll have to initialize the array to the required size (as opposed to a List that can grow dynamically):
int[] randomNum = new int[10];
for (int i = 0; i < randomNum.Length; i++)
{
randomNum[i] = numberGen.Next(1, 100);
}
Use a List<T>, thats is the scenario it was precisely designed for. Once you've finished adding elements to it, if you need an array then simply call ToArray():
var myList = new List<int>();
//add random number of random numbers
var myArray = myList.ToArray();

how to create a random int[] [duplicate]

This question already has answers here:
Most efficient way to randomly "sort" (Shuffle) a list of integers in C#
(13 answers)
Closed 5 years ago.
I need to create a random array of int with certain parameters.
int[] test = new int[80];
Random random = new Random();
I need to assign 1's and 0's, randomly to the array. I know how to do that.
test[position] = Random.Next(0,2);//obviously with a for loop
But I need to have exactly 20 1's, but they need to be randomly positioned in the array. I don't know how to make sure that the 1's are randomly positioned, AND that there are exactly 20 1's. The rest of the positions in the array would be assigned 0.
I think you need to turn your thinking around.
Consider:
var cnt = 20;
while (cnt > 0) {
var r = Random.Next(0, 80);
if (test[r] != 1) {
test[r] = 1;
cnt--;
}
}
Expanding explanation based on comments from CodeCaster. Rather than generate a random value to place in the array, this code generates and index to set. Since C# automatically initializes the test array to 0 these values are already set. So all you need is to add your 1 values. The code generates a random index, tests it to see if it isn't 1, if so it sets the array element and decrements a count (cnt). Once count reaches zero the loop terminates.
This won't properly function if you need more values than 0 and 1 that is true. Of course the questions explicitly stated that these were the needed values.
"This causes horrible runtime performance". What!? Can you produce any prove of that? There is a chance that the index generated will collide with an existing entry. This chance increases as more 1's are added. Worst case is there is a 19/80 (~23%) chance of collision.
If you know you need exactly 20 of one value, a better way to go about this is to pre-populate the array with the required values and then shuffle it.
Something like this should work:
int[] array = new int[80];
for (int i = 0; i < 80; i++)
{
int val = 0;
if (i < 20)
{
val = 1;
}
array[i] = val;
}
Random rnd = new Random();
int[] shuffledArray = array.OrderBy(x => rnd.Next()).ToArray();
You can do
for (int i = 0; i < 20; i++)
{
var rand = random.Next(0,80);
if (test[rand] == 1)
{
i--;
continue;
}
test[rand] = 1;
}
Remaining are automatically zero.

C# selection of random numbers in range

I want to produce a selection of random numbers in a range between 1 and 30, ideally this number will alter (to a max of +10) but will always have a range of 1 - 30. I want to be able to do this several times when needed. The numbers that I want to produce within the range will vary in numbers eg maybe I will want only 2 or 5 numbers.
I thought I should produce a static class and use the same random instance with a method that accepts an integer which indicated the total number of numbers I require within the range? Obviously the numbers should be no identical numbers returned from the method for each call. But if one method call produces the same numbers as a previous call then thats fine, but ideally they should differ.
I'm not sure how I would code this or if I'm completely wrong?
Sample code:
public static class getMyNumbers
{
private static Random random = new Random();
public static int[] getThese(int i)
{
int[] wanted = new int[i];
// a loop to generate the numbers???
// this bit I'm not sure about the syntax
// new to c#
return wanted
}
}
Thanks
You just need to loop putting the numbers into the array:
public static int[] getThese(int i)
{
int[] wanted = new int[i];
for (int j = 0; j < i; ++j)
wanted[j] = random.Next(31);
return wanted;
}
Note that the parameter to random.Next() is an exclusive upper range, so passing 31 will generate random numbers between 0 and 30.
As an aside, note that it's customary to use n for a count and i for a loop variable, so it would probably be better to name your variables thus:
public static int[] GetThese(int n)
{
int[] result = new int[n];
for (int i = 0; i < n; ++i)
result[i] = random.Next(31);
return result;
}
Just because everybody loves Linq:
private static Random random = new Random();
public IEnumerable<int> GetRandomInts(int Amount, int Max = 30)
{
return Enumerable.Range(0, Amount).Select(a => random.Next(Max)+1);
}
For no duplicates...
return Enumerable.Range(1, Max).OrderBy(a => random.Next()).Take(Amount);

Unique number in random?

I know there are many questions on the net about it ,but I would like to know why my method fails
What Am i Doing wrong?
public class Generator
{
private static readonly Random random = new Random();
private static readonly object SyncLock = new object();
public static int GetRandomNumber(int min, int max)
{
lock (SyncLock)
{
return random.Next(min, max);
}
}
}
[TestFixture]
public class Class1
{
[Test]
public void SimpleTest()
{
var numbers=new List<int>();
for (int i = 1; i < 10000; i++)
{
var random = Generator.GetRandomNumber(1,10000);
numbers.Add(random);
}
CollectionAssert.AllItemsAreUnique(numbers);
}
}
EDIT
Test method is failing!! Sorry for not mentioning
Thanks for your time and suggestions
How can you possibly expect a sequence of 10,000 random numbers from a set of 10,000 possible values to be all unique unless you are extremely lucky? What you are expecting is wrong.
Flip a coin twice. Do you truly expect TH and HT to be the only possible sequences?
What makes you think random numbers should work any differently?
This output from a random number generator is possible:
1, 1, 1, 1, 1, 1, ..., 1
So is this:
1, 2, 3, 4, 5, 6, ..., 10000
In fact, both of those sequences are equally likely!
You seem to be under the misapprehension that the Random class generates a sequence of unique, though apparently random numbers. This is simply not the case; randomness implies that the next number could be any of the possible choices, not just any except one I've seen before.
That being the case, it is entirely unsurprising that your test fails: the probability that 10000 randomly generated integers (between 1 and 10000 no less) are unique is minuscule.
Random != Unique
The point here is that your code should model your problem and yours really doesn't. Random is not equal to unique. If you want unique, you need to get your set of values and shuffle them.
If you truly want random numbers, you can't expect them to be unique. If your (P)RNG offers an even distribution, then over many trials you should see similar counts of every value (see the Law of Large Numbers). Cases may show up that seem "wrong" but you can't discount that you hit that case by chance.
public static void FisherYatesShuffle<T>(T[] array)
{
Random r = new Random();
for (int i = array.Length - 1; i > 0; i--)
{
int j = r.Next(0, i + 1);
T temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
int[] array = new int[10000];
for (int i = 0; i < array.Length; i++) array[i] = i;
FisherYatesShuffle(array);
I think you failed to mention that your test method is failing.
It is failing because your random generator is not producing Unique numbers. I'm not sure how it would under it's current condition.

Categories