c# unique random number - c#

i'm trying to get X number of random number (where X is a variable) between 0 and 100 and add them to a row in a DataGridView. I'm using the code below, but the problem is i need it to be impossible to have the same number twice. Is there a way make sure i get unique random numbers?
int X = 20;
Random random = new Random();
int randomrow = random.Next(0, 100);
for (int i = 0; i < X; i++)
{
int randomNumber = random.Next(0, 100);
data.Rows[randomrow][3] = randomNumber;
}
Thanks for the help!

Split your problem in two:
Create a list of X random, unique numbers. There are numerous ways to do that:
a. Create a list of all numbers 0-100 and then shuffle them. OR
b. Keep a hash set of all the numbers you already created (in addition to the list) and only add a new one if it has not been added before.
Afterwards, loop through the list and the data rows simultaneously and insert the values into the rows.

Here's the simple way to do it without creating a shuffle method for the List (though there are examples of that). Basically create a list of all possible integers, populate the list, then sort by new GUIDs.
int X = 20;
var RowNumbers = new List<int>();
for (int i = 0; i < X; i++)
RowNumbers.Add(i);
foreach (int i in RowNumbers.OrderBy(f => Guid.NewGuid()))
{
data.Rows[i][3] = i;
}

You would need to compare the numbers you have already used to the next one you get from random.Next. If you have already used it, pick another. I also like Heinzi's answer.

Here is algorithm without shuffling and previous result using:
var max = 100; // max available value
var count = 20; // number of random numbers
var random = new Random();
var rest = (double)max;
for (int i = 0; i < max; i++, rest--)
{
if (count / rest > random.NextDouble())
{
Console.WriteLine(i); // here is your random value
count--;
if (count == 0)
{
break;
}
}
}

Related

Way to extract positive and negative numbers from one array to another two (positive and negative)

I'm studying c# and I was wondering if there is any way to extract positive and negative numbers (integers) from one array to others two, one that contains the positive numbers and the other negative ones
I've tried something like
public static void Main(string[] args)
{
int[] num = new int[50];
Random objeto = new Random();
int i = 0;
for (i = 1; i <= 50; i++)
{
Console.WriteLine("Random numbers:");
num[1] = objeto.Next(-50, 50);
Console.WriteLine(num[1] + "");
}
Console.ReadKey(); here
}
I have to create two other arrays
int[] positive_numbers = int new [N]
int[] negative_numbers = int new [N]
And I guess I should create a method, but I do not know how I have to do it.
You could use LINQ:
var positiveNumbers = numbers.Where(n => n > 0).ToArray();
var negativeNumbers = numbers.Where(n => n < 0).ToArray();
Or an alternative approach is to count how many even and odd numbers you have, create two arrays and then populate them. This assumes that you want the arrays to be exactly the correct length.
// Variables to store counts of positive and negative numbers
int positiveCount = 0;
int negativeCount = 0;
// Because we'll be building new arrays, we need to track our
// position within them, so we create two variables to do that
int positiveIndex = 0;
int negativeIndex = 0;
// loop through once to count the positive and negative numbers
foreach (var number in numbers)
{
if (number > 0)
{
++positiveCount; // same as positiveCount = positiveCount + 1
}
else if (number < 0)
{
++negativeCount;
}
}
// now we know how many +ve and -ve numbers we have,
// we can create arrays to store them
var positiveNumbers = new int[positiveCount];
var negativeNumbers = new int[negativeCount];
// loop through and populate our new arrays
foreach (var number in numbers)
{
if (number > 0)
{
positiveNumbers[positiveIndex++] = number;
// number++ will return the value of number before it was incremented,
// so it will first access positiveNumbers[0] and then positiveNumbers[1], etc.
// each time we enter this code block.
}
else if (number < 0)
{
negativeNumbers[negativeIndex++] = number;
}
}
An alternative approach to the initial count would be to define both arrays to be the same length as the numbers array, and then use positiveIndex and negativeIndex to determine the maximum populated index in the positiveNumbers and negativeNumbers arrays. The downside is that it uses a little more memory (but memory is cheap for such a small set), and the upside is that you only have to loop through once so it's more performant.
If your situation allows, it might be easier to use generic lists instead:
var positiveNumbers = new List<int>();
var negativeNumbers = new List<int>();
foreach (var number in numbers)
{
if (number > 0)
{
positiveNumbers.Add(number);
}
else if (number < 0)
{
negativeNumbers.Add(number);
}
}
Generic lists are basically fancy wrappers around internal arrays. The list starts out with an array of a relatively small size. As you add items to the list, more arrays are generated to store all of your items. You can see the current overall size of the internal arrays by checking the list's .Capacity property. Do not confuse Capacity with Count. Count shows the number of items actually in your list, whereas Capacity shows the number of items your list can hold before expanding.
Note that in these answers, zeroes will be excluded since you only asked for positive and negative numbers, and zero is neither. As highlighted by Max Play's comment, you should change > to >= if you consider zero to be positive.
Assuming you'll handle 0 as positive, add a method to check for positive.
private static bool isNegtive(int number)
{
return number < 0;
}
I'd use list over array for unknown quantities. It'd go something like this:
public static void SeparateRandomNumbers()
{
IList<int> positive_numbers = new List<int>();
IList<int> negative_numbers = new List<int>();
Random objeto = new Random();
for (int i = 0; i < 50; i++)
{
var number = objeto.Next(-50, 50);
if (isNegtive(number))
{
negative_numbers.Add(number);
}
else
{
positive_numbers.Add(number);
}
}
}

List of numbers without repetition [duplicate]

This question already has answers here:
How to make this code work without repeating the numbers? [duplicate]
(3 answers)
Closed 4 years ago.
I need to print random numbers from 1 to 99 without repeating them.
The following code gives me stack overflow.
int newNumb= Random.Range(1, 99);
if(acum.Count > 0)
{
while (acum.Contains(newNumb))
{
newNumb= Random.Range(1, 99);
}
}
The typical solution to this problem is to generate the sequential ordered range from 1 to 99 and then shuffle it:
static Random _random = new Random();
public static void Shuffle<T>(IList<T> items)
{
for (int i = thisList.Count - 1; i > 0; i--)
{
int j = _random.Next(0, i);
T tmp = items[i];
items[i] = items[j];
items[j] = tmp;
}
}
var numbers = Enumerable.Range(1,99).ToList();
Shuffle(numbers);
foreach (var number in numbers)
{
Console.WriteLine(number);
}
This will generate a list of random integers, each time a different one, and add it to a list.
The shuffle method is better, but since the range is so limited, also discarding duplicate numbers could work.
Over 100 runs, measuring the elapsed time with a StopWatch(), the list generation never went over 200 Ticks.
The shuffled list 5x times (1029~1395 Ticks) on my machine.
If the list count is set to a value > then the upper range limit (100+ in this case), the the generation procedure will of course never end. There are not enough distinct random values to fill the list.
Random random = new Random();
List<int> acum = new List<int>();
while (acum.Count < 99)
{
int Number = random.Next(1, 100);
if (!acum.Contains(Number))
{
acum.Add(Number);
}
}
To verify the result, order the list and see that it's ordered from 1 to 99:
List<int> acum2 = acum.OrderBy(n => n).ToList();
the best way to do this would be to generate all the necessary numbers, and pull from that list until its empty, creating a new order; this is commonly known as shuffling.
your current code takes way too long, you need to track which numbers have been chosen, and only choose from the remaining ones. in psudocode
generate list
while list not empty
choose number from list
remove it from list
add to new list
Do this simply:
var list = new List<int>();
for (int i = 0; i < 99; i++)
{
list.Add(i);
}
var resultList = list.OrderBy(i => Guid.NewGuid());
Or as suggested by #Camilo:
var resultList = Enumerable
.Range(0, 99)
.OrderBy(i => Guid.NewGuid());
UPDATE
This solution seems to be inefficient. Please use fischer-yates shuffle (shown in #Joel's answer).
Non efficient way (see comments):
Random rand = new Random();
HashSet<int> randomHashSet = new HashSet<int>();
while (randomHashSet.Count < 99)
randomHashSet.Add(rand.Next(1, 100));
List<int> randomList = randomHashSet.ToList();
Update
Efficient way:
Random r = new Random();
var result = Enumerable.Range(1, 99).ToList();
for (int i = 0, j = r.Next(0, 99); i < 99; i++, j = r.Next(0, 99))
result[i] = result[i] + result[j] - (result[j] = result[i]); // Swap

How do I check for duplicates in my array?

How do I store a random number into my array, but only if there is not a duplicate already inside the array? My code below still inputs a duplicate number.
Random rand = new Random();
int[] lotto = new int [6];
for (int i = 0; i < lotto.Length; i++)
{
int temp = rand.Next(1, 10);
while (!(lotto.Contains(temp)))//While my lotto array doesn't contain a duplicate
{
lotto[i] = rand.Next(1, 10);//Add a new number into the array
}
Console.WriteLine(lotto[i]+1);
}
Try this:
Random rand = new Random();
int[] lotto = new int[6];
for (int i = 0; i < lotto.Length; i++)
{
int temp = rand.Next(1, 10);
// Loop until array doesn't contain temp
while (lotto.Contains(temp))
{
temp = rand.Next(1, 10);
}
lotto[i] = temp;
Console.WriteLine(lotto[i] + 1);
}
This way the code keeps generating a number until it finds one that isn't in the array, assigns it and moves on.
There are a lot of ways to 'shuffle' an array, but hopefully this clears up the issue you were having with your code.
What you really want is to shuffle the numbers from 1 to 9 (at least that's what your example is implying) and then take the first 6 elements. Checking for duplicates is adding unnecessary indeterminism and really is not needed if you have a shuffle.
E.g take this accepted answer for a Fisher-Yates shuffle and then take the first 6 elements for lotto.
This would then look like this:
lotto = Enumerable.Range(1,9)
.Shuffle()
.Take(6)
.ToArray();

Why am I getting duplicates?

I've built a Keno game, and it picks 20 random numbers out of an arraylist, NumbersToPickFrom. I generate a random number and then check if that number is currently in the numbers available to pick from. If it is, I add it to my arraylist of numbers that will be used as the lottery numbers, randomPicks, and then I remove it from the available numbers. If it's not in the list, that means it's already been picked, and I need a new number. I use a goto to start over. I thought it was working fine, but it seems I've been getting duplicates. Am I using the ArrayList.Remove function wrong? If it's removed, I shouldn't be getting duplicates in my final listing of random picks. If anybody can see where I missed something, that would be helpful. The below code is just the code involved in what I'm talking about.
private void GeneratePicks()
{
for (int i = 1; i <= 20; )
{
Retry:
int rInt = GenerateRandomPick();
if (NumbersToPickFrom.Contains(rInt))
{
RandomPicks.Add(rInt);
NumbersToPickFrom.Remove(rInt);
i++;
//PickBox.Text += rInt + " ,";
RandomPicks.Sort();
}
else
{
goto Retry;
}
}
}
private int GenerateRandomPick()
{
int rInt = rand.Next(1,81);
return rInt;
}
private void initializeArray()
{
for (int i = 1; i <= 80; i++)
{
NumbersToPickFrom.Add(i);
}
}
I ran your code and didn't get any duplicates at all.
Nevertheless, the approach of repeatedly picking random numbers and comparing to the shrinking list isn't the best way to do this.
Try this instead:
RandomPicks =
Enumerable
.Range(1, 80)
.OrderBy(n => rand.Next())
.Take(20)
.OrderBy(n => n)
.ToList();
I found that your code is working fine.
I added the following public variables to make it work though (on my machine)
List<int> NumbersToPickFrom = new List<int>();
List<int> RandomPicks = new List<int>();
Random rand = new Random();
Though on the second run, i found that the number of items in RandomPicks have doubled and there were duplicates as well, so I changed initializeArray() as below
private void initializeArray()
{
for (int i = 1; i <= 80; i++)
{
NumbersToPickFrom.Add(i);
}
RandomPicks.Clear(); // Added this to clear the existing values in the list.
}
If you want to do it "old school" and actually watch what's happening, change your GeneratePicks() method to this:
private void GeneratePicks()
{
RandomPicks = new List<int>();
initializeArray();
for (int i = 0; i < 20; ++i)
{
int randomIndex = rand.Next(1, 80 - i);
int randomPick = NumbersToPickFrom[randomIndex];
RandomPicks.Add(randomPick);
NumbersToPickFrom[randomIndex] = NumbersToPickFrom[80 - i - 1];
}
RandomPicks.Sort();
}
This will run through exactly 20 times and guarantee non-duplicates.
I can't see any error in your code, and tested your code by running it 100000 times and didn't get any duplicates.
There are however better methods for getting random numbers. One easy improvement would be to randomly pick a number from the NumbersToPickFrom list instead of just picking a number, then you don't need the inner loop.
There is a nicer way to pick lottery numbers. You can loop through the numbers and calculate the probability that each number should be picked. The probability of a number being picked is PicksLeft / NumbersLeft, for example the probability for the number 1 to be picked is 20 / 80, and then the probability changes depending on which numbers are picked:
private void GeneratePicks() {
int pick = 20;
for (int n = 1; pick > 0; n++) {
if (rand.Next(81 - n) < pick) {
RandomPicks.Add(n);
pick--;
}
}
}
As the numbers are picked in order, you don't even have to sort the numbers afterwards, and you don't need the NumbersToPickFrom list.

Randomly pick 4 elements from an array using c#

I am trying to use random function in C# to randomly pick four from an array addetailsID which has over six elements.
I am placing these randomly picked into an another array strAdDetailsID:
string[] strAdDetailsID = new string[4];
for (int i = 0; i < 4; i++)
{
Random random = new Random();
int index = random.Next(0, addetailsID.Length);
value = addetailsID[index].ToString();
strAdDetailsID[i] = value;
}
Sometimes, I get two of the same values from the six elements. How can I get all four unique values to be picked?
You might be better off shuffling the array, and then choosing the first 4 elements.
You could do it with LINQ with this method.
List<string> list = new List<string>() { "There", "Are", "Many", "Elements", "To", "Arrays" };
foreach (var item in list.OrderBy(f => Guid.NewGuid()).Distinct().Take(4))
{
Console.WriteLine(item);
}
You have an issue with your placement of Random random ... but I believe you're attacking this the wrong way.
This could be solved by randomly ordering the source and taking the first 4 items.
var result = addetails.OrderBy(x => Guid.NewGuid()).Take(4).ToArray();
Assuming the contents of addetails are unique (like you imply), you will always get 4 unique values here. Using random correctly, it's still possible to get repeats (because it's random).
You need to generate 4 unique indices first, then pull the random values from the source array:
string[] addetailsID = new string[20]; // this is the array I want to index into
// generate the 4 unique indices into addetailsID
Random random = new Random();
List<int> indices = new List<int>();
while (indices.Count < 4)
{
int index = random.Next(0, addetailsID.Length);
if (indices.Count == 0 || !indices.Contains(index))
{
indices.Add(index);
}
}
// now get the 4 random values of interest
string[] strAdDetailsID = new string[4];
for (int i = 0; i < indices.Count; i++)
{
int randomIndex = indices[i];
strAdDetailsID[i] = addetailsID[randomIndex];
}
Put them in a list and remove the selected element from the list once it has been chosen.
The following algorithm works pretty well, and doesn't require extra storage or pre-shuffling. It does change the order of the source array, so if that's not feasible, then the pre-shuffling approach is best.
In pseudo-code:
result = []
For i = 0 to numItemsRequired:
randomIndex = random number between i and source.length - 1
result.add(source[randomIndex])
swap(source[randomIndex], source[i])
In C#:
string[] strAdDetailsID = new string[4];
Random rand = new Random();
for (int i = 0; i < 4; i++)
{
int randIndex = rand.Next(i, adDetailsID.Length);
strAddDetails[i] = adDetailsID[randIndex];
string temp = adDetailsID[randIndex];
adDetailsID[randIndex] = adDetailsID[i];
adDetails[i] = temp;
}
Use a list instead and drop every item that is already used:
List<string> addetailsID = new List<string>{"1","2","3","4","5","6"};
string[] strAdDetailsID = new string[4];
Random random = new Random();
for (int i = 0; i < 4; i++)
{
int index = random.Next(0, addetailsID.Count);
string value = addetailsID[index].ToString();
addetailsID.RemoveAt(index);
strAdDetailsID[i] = value;
}
strAdDetailsID.Dump();
Well, you should select random items one by one, not considering the already-picked items when selecting the next one. This must be faster than shuffling.
If the source list is small, you can just make a copy and remove the chosen items from it. Otherwise, you go like this:
(let n be the number of items in your array)
let S be the set of chosen indices; S = empty at the beginning
choose a random index i from 0 to n-1-size(S)
for each index from S that is smaller than i (starting from the smallest index!), add one to i
now i is a chosen index, add it to S.
return to step 2 until your set contains 4 elements.

Categories