how to create a random int[] [duplicate] - c#

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.

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.

Fill an array with unique random integers [duplicate]

This question already has answers here:
Randomize a List<T>
(28 answers)
Closed 5 years ago.
I want to fill a small array with unique values from a bigger array. How do I check the uniqueness?
Here's what I have:
int[] numbers45 = new int[45];
for (int i = 0; i <= 44; i++) // I create a big array
{
numbers45[i] = i + 1;
}
Random r = new Random();
int[] draw5 = new int[5]; //new small array
Console.WriteLine("The 5 draws are:");
for (int i = 1; i <= 4; i++)
{
draw5[i] = numbers45[r.Next(numbers45.Length)]; //I fill the small array with values from the big one. BUT the values might not be unique.
Console.WriteLine(draw5[i]);
}
There are multiple ways to do what you are asking.
First off, though, I would recommend to use one of the classes which wraps the array type and adds some extra functionality you could use (in this case a List would probably be a perfect structure to use)!
One way to handle this is to check if the value is already in the draw5 array. This can be done with (for example) the List<T>.Contains(T) function, and if it exists, try another.
Personally though, I would probably have randomized the first array with the OrderBy linq method and just return a random number, like:
numbers45.OrderBy(o => random.Next());
That way the numbers are already random and unique when it is supposed to be added to the second list.
And a side note: Remember that arrays indexes starts on index 0. In your second loop, you start at 1 and go to 4, that is, you wont set a value to the first index.
You could just run for (int i=0;i<5;i++) to get it right.
Inspired by Jite's answer, I changed to use Guid to randomize the numbers
var randomized = numbers45.OrderBy(o => Guid.NewGuid().ToString());
Then you could take the draws by:
var draws = randomized.Take(5).ToArray;
HashSet<int> hs = new HashSet<int>();
int next = random.next(45);
while(hs.Length <=5)
{
if(!hs.Contains(array[next]))
hs.Add(array[next]);
next = random next(45);
}

How to resolve an "IndexOutOfRange exception" error? [duplicate]

This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 6 years ago.
I can't understand what's wrong.
static int WinningColumn()
{
Random rnd = new Random(46);
int[] winningnumbers = new int[6];
int[] Check = new int[46];
int i;
for (i = 0; i < winningnumbers.Length; i++)
{
winningnumbers[i] = rnd.Next(46);
Check[winningnumbers[i]]++;
if (Check[winningnumbers[i]] > 1)
{
i--;
continue;
}
The error happens here:
}
return winningnumbers[i];
}
When you exit from the for loop the indexer variable i has a value bigger than the max index possible (It is the condition that breaks the loop).
In your case the variable i has the value of 6 but the max index possible for the array winningnumbers is 5. (0 to 5 are six integer elements).
It is not clear what is your intent but supposing that your purpose is to generate six winning numbers ranging from 0 to 45 then your code should be rewritten and simplified in this way
static List<int> WinningColumn()
{
// Do not initialize Random with a fixed value
// You will get always the same 'random' sequence
Random rnd = new Random();
// Create a list to store the winners
List<int> winningnumbers = new List<int>();
int i = 0;
while(i < 6)
{
int newNumber = rnd.Next(46);
if(!winningnumbers.Contains(newNumber))
{
// If the list doesn't contain the number the add it and increment i
// Otherwise run the loop again....
winningnumbers.Add(newNumber);
i++;
}
}
// This returns the whole list to the caller,
// you can use it as an array
return winningnumbers;
}
Notice that your actual code contains a bug in the declaration of the Random number generator. You pass an initial seed and thus, everytime you call this method, the random generator starts again with the same sequence of numbers. The result would be an identical list of numbers. Not very random to me
If you don't pass anything then the generator is initialized with the system time and thus should be different every time you call this method.
I don't know what you want to achieve here.
But the loop would terminate when i becomes 6.
So you are basically trying to access winningnumbers[6] which is incorrect since winningnumbers array has length 6 so you can use index from 0 till 5.
You may try with winningnumbers [i-1]

Random selection for a variable set with a guarantee of every item at least once

I am working on a game in c# but that detail is not really neccessary to solve my problem.
At I high level here is what I want:
I have a set that could have any number of items in it.
I want to randomly select 10 items from that set.
If the set has less than 10 items in then I expect to select the same
item more than once.
I want to ensure every item is selected at least once.
What would be the algorithm for this?
Sorry I'm not sure if this is an appropriate place to ask, but I've got no pen and paper to hand and I can't quite get my head round what's needed so appreciate the help.
In addition I might also want to add weights to the items to
increase/decrease chance of selection, so if you are able to
incorporate that into your answer that would be fab.
Finally thought I should mention that my set is actually a List<string>, which might be relevent if you prefer to give a full answer rather than psuedo code.
This is what I use to randomize an array. It takes an integer array and randomly sorts that list a certain amount of times determined by the random number (r).
private int[] randomizeArray(int[] i)
{
int L = i.Length - 1;
int c = 0;
int r = random.Next(L);
int prev = 0;
int curr = 0;
int temp;
while (c < r)
{
curr = random.Next(0, L);
if (curr != prev)
{
temp = i[prev];
i[prev] = i[curr];
i[curr] = temp;
c++;
}
}
return i;
}
If you look for effective code, my answer isnt it. In theory, create some collection you can remove from that will mirror your set. Then select random member of the object from it ...and remove, this will garantee items wont repeat(if possible).
Random rnd = new Random();
List<int> indexes = new List<int>(items.Count);
for (int i = 0; i < items.Count; i++)
indexes.Add(i);
List<string> selectedItems = new List<string>(10);
int tmp;
for(int i = 0; i < 10; i++)
{
tmp = rnd.Next(1,10000); //something big
if(indexes.Count > 0)
{
selectedItems.Add(yourItems[indexes[tmp%indexes.Count]]);
indexes.RemoveAt(tmp%indexes.Count);
}
else
selectedItems.Add(yourItems[rnd.Next(0,9)]); //you ran out of unique items
}
where items is your list and yourItems is list of selected items, you dont need to store them if you want process them right away
Perhaps shuffle the collection and pick elements from the front until you have the required amount.
Once you've gone through all the elements, you should perhaps shuffle it again, so you don't just repeat the same sequence.
The basic algorithm for shuffling: (in pseudo-code)
for i from n − 1 downto 1 do
j ← random integer with 0 ≤ j ≤ i
exchange a[j] and a[i]
With the above algorithm (or a minor variation), it's possible to just shuffle until you reach the required number of elements, no need to shuffle the whole thing.

Generating 2 Random Numbers that are Different C#

I would like to generate two random numbers that are different from each other. For example, if the first random number generates 5, I want the next random number generated to not equal 5. This is my code thus far:
Random ran = new Random();
int getRanNum1 = ran.Next(10);
int getRanNum2 = ran.Next(10);
How do I tell getRandNum2 to not equal the value generated in getRandNum1?
With a loop:
int getRanNum2 = ran.Next(10);
while(getRanNum2 == getRanNum1)
getRanNum2 = ran.Next(10);
While the loop-and-check approach is likely suitable here, a variant of this question is "How to get N distinct random numbers in a range (or set)?"
For that, one possible alternative (and one that I like, which is why I wrote this answer) is to build said range (or set), shuffle the items, and then take the first N items.
An implementation of the Fischer-Yates shuffle can be found in this answer. Slightly cleaned up for the situation:
void Shuffle (int arr[]) {
Random rnd = new Random();
for (int i = arr.Length; i > 1; i--) {
int pos = rnd.Next(i);
var x = arr[i - 1];
arr[i - 1] = arr[pos];
arr[pos] = x;
}
}
// usage
var numbers = Enumerable.Range(0,10).ToArray();
Shuffle(numbers);
int getRanNum1 = numbers[0];
int getRanNum2 = numbers[1];
Since we know that only N (2) elements are being selected, the Shuffle method above can actually be modified such that only N (2) swaps are done. This is because arr[i - 1], for each i, is only swapped once (although it can be swapped with itself). In any case, this left as an exercise for the reader.

Categories