What is an efficient way of generating N unique numbers within a given range using C#? For example, generate 6 unique numbers between 1 and 50. A lazy way would be to simply use Random.Next() in a loop and store that number in an array/list, then repeat and check if it already exists or not etc.. Is there a better way to generate a group of random, but unique, numbers?
To add more context, I would like to select N random items from a collection, using their index.
thanks
Take an array of 50 elements: {1, 2, 3, .... 50}
Shuffle the array using any of the standard algorithms of randomly shuffling arrays. The first six elements of the modified array is what you are looking for. HTH
For 6-from-50, I'm not too sure I'd worry about efficiency since the chance of a duplicate is relatively low (30% overall, from my back-of-the-envelope calculations). You could quite easily just remember the previous numbers you'd generated and throw them away, something like (pseudo-code):
n[0] = rnd(50)
for each i in 1..5:
n[i] = n[0]
while n[1] == n[0]:
n[1] = rnd(50)
while n[2] == any of (n[0], n[1]):
n[2] = rnd(50)
while n[3] == any of (n[0], n[1], n[2]):
n[3] = rnd(50)
while n[4] == any of (n[0], n[1], n[2], n[3]):
n[4] = rnd(50)
while n[5] == any of (n[0], n[1], n[2], n[3], n[4]):
n[5] = rnd(50)
However, this will break down as you move from 6-from-50 to 48-from-50, or 6-from-6, since the duplicates start getting far more probable. That's because the pool of available numbers gets smaller and you end up throwing away more and more.
For a very efficient solution that gives you a subset of your values with zero possibility of duplicates (and no unnecessary up-front sorting), Fisher-Yates is the way to go.
dim n[50] // gives n[0] through n[9]
for each i in 0..49:
n[i] = i // initialise them to their indexes
nsize = 50 // starting pool size
do 6 times:
i = rnd(nsize) // give a number between 0 and nsize-1
print n[i]
nsize = nsize - 1 // these two lines effectively remove the used number
n[i] = n[nsize]
By simply selecting a random number from the pool, replacing it with the top number from that pool, then reducing the size of the pool, you get a shuffle without having to worry about a large number of swaps up front.
This is important if the number is high in that it doesn't introduce an unnecessary startup delay.
For example, examine the following bench-check, choosing 10-from-10:
<------ n[] ------>
0 1 2 3 4 5 6 7 8 9 nsize rnd(nsize) output
------------------- ----- ---------- ------
0 1 2 3 4 5 6 7 8 9 10 4 4
0 1 2 3 9 5 6 7 8 9 7 7
0 1 2 3 9 5 6 8 8 2 2
0 1 8 3 9 5 6 7 6 6
0 1 8 3 9 5 6 0 0
5 1 8 3 9 5 2 8
5 1 9 3 4 1 1
5 3 9 3 0 5
9 3 2 1 3
9 1 0 9
You can see the pool reducing as you go and, because you're always replacing the used one with an unused one, you'll never have a repeat.
Using the results returned from that as indexes into your collection will guarantee that no duplicate items will be selected.
var random = new Random();
var intArray = Enumerable.Range(0, 4).OrderBy(t => random.Next()).ToArray();
This array will contain 5 random numbers from 0 to 4.
or
var intArray = Enumerable.Range(0, 10).OrderBy(t => random.Next()).Take(5).ToArray();
This array will contain 5 random numbers between 0 to 10.
int firstNumber = intArray[0];
int secondNumber = intArray[1];
int thirdNumber = intArray[2];
int fourthNumber = intArray[3];
int fifthNumber = intArray[4];
For large sets of unique numbers, put them in an List..
Random random = new Random();
List<int> uniqueInts = new List<int>(10000);
List<int> ranInts = new List<int>(500);
for (int i = 1; i < 10000; i++) { uniqueInts.Add(i); }
for (int i = 1; i < 500; i++)
{
int index = random.Next(uniqueInts.Count) + 1;
ranInts.Add(uniqueInts[index]);
uniqueInts.RemoveAt(index);
}
Then randomly generate a number from 1 to myInts.Count. Store the myInt value and remove it from the List. No need to shuffle the list nor look to see if the value already exists.
instead of using List use Dictionary!!
In case it helps anyone else, I prefer allocating the minimum number of items necessary. Below, I make use of a HashSet, which ensures that new items are unique. This should work with very large collections as well, up to the limits of what HashSet plays nice with.
public static IEnumerable<int> GetRandomNumbers(int numValues, int maxVal)
{
var rand = new Random();
var yieldedValues = new HashSet<int>();
int counter = 0;
while (counter < numValues)
{
var r = rand.Next(maxVal);
if (yieldedValues.Add(r))
{
counter++;
yield return r;
}
}
}
generate unique random nos from 1 to 40 :
output confirmed :
class Program
{
static int[] a = new int[40];
static Random r = new Random();
static bool b;
static void Main(string[] args)
{
int t;
for (int i = 0; i < 20; i++)
{
lab: t = r.Next(1, 40);
for(int j=0;j<20;j++)
{
if (a[j] == t)
{
goto lab;
}
}
a[i] = t;
Console.WriteLine(a[i]);
}
Console.Read();
}
}
sample output :
7
38
14
18
13
29
28
26
22
8
24
19
35
39
33
32
20
2
15
37
Related
I am building a tournament schedule with round robin style match order. I have an algorithm set up to build the matches, however the match order is not what I am looking for. I am struggling to develop an algorithm that will build the matches in my desired order. See example below with a 6 team bracket. Each vertical line represents a row in the tournament. The far left number represents the base team seed and who they will play in each round.
Note: The only thing that is really important to me is that the 1 and 2 seed play in the last round of the tournament. And preferably that 1 v 6, 2 v 5, 3 v 4 happens in the first round of the tournament. All other matches aren't as important. Thank you in advance for any help you can provide.
1: 6 5 4 3 2
2: 5 4 3 6 1
3: 4 6 2 1 5
4: 3 2 1 5 6
5: 2 1 6 4 3
6: 1 3 5 2 4
Here is my current code:
int numTeams = teamList.Count;
int rounds = (numTeams - 1);
int halfSize = numTeams / 2;
List<Team> teams = new List<Team>();
teams.AddRange(teamList); // Copy all the elements.
teams.RemoveAt(0); // To exclude the first team.
int teamSize = teams.Count;
for (int round = 0; round < rounds; round++)
{
int teamIdx = round % teamSize;
Team baseTeam1 = teams[teamIdx];
Team baseTeam2 = teamList[0];
// save each team to a match
for (int idx = 1; idx < halfSize; idx++)
{
int firstTeamIdx = (round + idx) % teamSize;
int secondTeamIdx = (round + teamSize - idx) % teamSize;
Team subTeam1 = teams[firstTeamIdx];
Team subTeam2 = teams[secondTeamIdx];
// save each team to a match
}
}
Sometimes asking the question helps figure out the answer. As it turns out, my current algorithm was creating what I wanted, just in opposite order. What I did to fix was create a new varible inside the first for loop called actualRound:
int actualRound = rounds - round; // this will reverse the round order
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I would like to generate all the possible numbers that have length n and each digit of my number has a value from the set {1,2,...,n-1}, as an array. In other words, I would like to list all the base n numbers with length n that do not include 0.
Right now, the only way I can think to do it is by nesting n for loops, and assigning myArray[i] with the (i+1)th loop, i.e.
int n;
int[] myArray = new int[n];
for (int i1 = 1; i1 < n; i1++)
myArray[0]=i1;
for (int i2 = 1; i2 < n; i2++)
myArray[1]=i2;
// and so on....
for (int in = 1; in < n; in++)
{
myArray[n]=in;
foreach (var item in myArray)
Console.Write(item.ToString());
Console.Write(Environment.NewLine);
}
and then printing each array at the innermost loop. The obvious issue is that for each n, I need to manually write n for loops.
From what I've read, recursion seems to be the best way to replace nested for loops, but I can't seem figure out how to make a general method for recursion either.
EDIT
For example, if n=3, I would like to write out 1 1 1, 1 1 2, 1 2 1, 1 2 2, 2 1 1, 2 1 2, 2 2 1, 2 2 2.
We are not limited to n<11. For example, if n=11, we would output
1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 2
1 1 1 1 1 1 1 1 1 1 3
...
1 1 1 1 1 1 1 1 1 1 10
1 1 1 1 1 1 1 1 1 2 1
1 1 1 1 1 1 1 1 1 2 2
1 1 1 1 1 1 1 1 1 2 3
...
1 1 1 1 1 1 1 1 1 9 10
1 1 1 1 1 1 1 1 1 10 1
1 1 1 1 1 1 1 1 1 10 2
1 1 1 1 1 1 1 1 1 10 3
...
10 10 10 10 10 10 10 10 10 9 10
10 10 10 10 10 10 10 10 10 10 1
10 10 10 10 10 10 10 10 10 10 2
...
10 10 10 10 10 10 10 10 10 10 10
So, a digit of a number may be any value between and including 1 and 10. The array myArray is simply used to get one of these numbers, then we print it, and go on to the next number and repeat.
As always, when thinking in recursive solutions, try to solve the problem using immutable structures; everything is much simpler to understand.
So first of all, lets build ourselves a fast little immutable stack that will help us keep track of the number we are currently generating (while not worrying about what other numbers are being generated in the recursive call...remember, immutable data can't change!):
public class ImmutableStack<T>: IEnumerable<T>
{
public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>();
private readonly T first;
private readonly ImmutableStack<T> rest;
public int Count { get; }
private ImmutableStack()
{
Count = 0;
}
private ImmutableStack(T first, ImmutableStack<T> rest)
{
Debug.Assert(rest != null);
this.first = first;
this.rest = rest;
Count = rest.Count + 1;
}
public IEnumerator<T> GetEnumerator()
{
var current = this;
while (current != Empty)
{
yield return current.first;
current = current.rest;
}
}
public T Peek()
{
if (this == Empty)
throw new InvalidOperationException("Can not peek an empty stack.");
return first;
}
public ImmutableStack<T> Pop()
{
if (this == Empty)
throw new InvalidOperationException("Can not pop an empty stack.");
return rest;
}
public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
That's easy. Note how the stack reuses data. How many empty immutable structs will there be in our little program? Only one. And stacks containing the sequence 1->2->4? Yup, only one.
Now, we implement a recursive function that just keeps adding numbers to the stack until we reach our "bail out" condition. Which is? When the stack contains n elements. Easy peasy:
private static IEnumerable<int> generateNumbers(ImmutableStack<string> digits, IEnumerable<string> set, int length)
{
if (digits.Count == length)
{
yield return int.Parse(string.Concat(digits));
}
else
{
foreach (var digit in set)
{
var newDigits = digits.Push(digit);
foreach (var newNumber in generateNumbers(newDigits, set, length))
{
yield return newNumber;
}
}
}
}
Ok, and now we just need to tie it alltogether with our public method:
public static IEnumerable<int> GenerateNumbers(int length)
{
if (length < 1)
throw new ArgumentOutOfRangeException(nameof(length));
return generateNumbers(ImmutableStack<string>.Empty,
Enumerable.Range(1, length - 1).Select(d => d.ToString(CultureInfo.InvariantCulture)),
length);
}
And sure enough, if we call this thing:
var ns = GenerateNumbers(3);
Console.WriteLine(string.Join(Environment.NewLine,
ns.Select((n, index) => $"[{index + 1}]\t: {n}")));
We get the expected output:
[1] : 111
[2] : 211
[3] : 121
[4] : 221
[5] : 112
[6] : 212
[7] : 122
[8] : 222
Do note that the total amount of numbers generated of a specified length n is (n - 1) ^ n which means that for relatively small values of length you are going to get quite an amount of numbers generated; n = 10 generates 3 486 784 401...
Given the following:
for(int seed = 0; seed < 100; seed++) {
var random = new Random(seed);
var roll = (random.Next() % 6) + 1;
Console.Write(roll + " ");
}
I'm seeing a clear pattern in the output:
1 1 2 2 3 3 4 4 5 5 6 6 1 1 1 2 2 3 3 4 4 5 5 6 6
1 1 2 2 3 3 4 4 5 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 6
1 1 2 2 3 3 4 4 4 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 6
1 1 2 2 3 3 3 4 4 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 6
I do understand that recreating a new Random object every time with a sequential seed isn't the "proper" way of using the class, and that strictly speaking I should be keep the Random instance around, calling Next() on it each time.
However, my use case is that I need to be able to exit my program and restore the state at any moment, and continue the sequence of numbers.
I also need the user to be able to set a seed manually, so I was hoping to be able to do something like:
var random = new Random(userSeed + nextValueIndex);
var chosenValue = random.Next();
I've also tried random.Next(min, max), and it gives different results, but also in a clear pattern.
Clearly my approach isn't the right way to use the Random class, but what is, for my use case?
I understand that random number generation is a very complex topic, so while I'm sort of interested in an explanation of why this is happening, I'm most interested in a practical (easy?) solution ;-)
Here's my solution, which seems to work nicely. Rather than seeding Random with userSeed + index (where index counts from zero), I simply cache the exact result from Random as previousRandom, and then seed with userSeed + previousRandom. That way, I get nice big numbers as the seed, and it avoids the sequential pattern. (previousRandom is initialised as zero, but that's not a problem.)
So, this is roughly what my code looks like:
var nextSeed = userSeed + this.previousRandom;
var randomObj = new Random(nextSeed);
var nextRandomValue = randomObj.Next ();
var chosenValue = (nextRandomValue % randomRange) + rangeMin;
this.previousRandom = nextRandomValue;
return chosenValue;
The one remaining thing I should probably do is make sure that userSeed + previousRandom doesn't overflow (or overflows predictably), because previousRandom might get very close to int's upper bound (up to whatever range I allow for userSeed).
I've been trying to simulate rolling a 6-faces dice in C#. I thought using RNGCSP was better than Random because it is more secure.
I tried using MSDN's example code to achieve this, but there are a few things that I didn't understand from the code:
How do you generate 5 digit long numbers with RNGCSP?
How do you generate numbers from 1 to 6 (excluding zeroes)?
1. How do you generate 5 digit long numbers with RNGCSP?
For the numbers, you can use a range. You'll have to think of the lower bound yourself though. Ranges for number are treated in RNGCryptoServiceProvider.
So for a 5 digit number min would be 0 or 10000 and max would be 100000, because max is exclusive.
2. How do you generate numbers from 1 to 6 (excluding zeroes)?
Basically the same way, you generate a range [1, 7) where 7 - the max value - is exclusive.
If you just want a dice result you can just do something like this (untested!):
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] singleByteBuf = new byte[1];
int max = Byte.MaxValue - Byte.MaxValue % 6;
while (true) {
rng.GetBytes(singleByteBuf);
int b = singleByteBuf[0];
if (b < max) {
return b % 6 + 1;
}
}
Basically the same idea, but is only requests 1 byte at a time from the RNGCryptoServiceProvider, so it doesn't waste 3 additional bytes.
If you have a NxN matrix of positive integers, and you are asked to select exactly one element from each row and column, so that the sum of the selected elements is minimized, how can it be solved?
I think it is about Dynamic Programming. I have tried to minimize the time O(n!) using memoization:
Dictionary<byte[,], int>[] memo = new Dictionary<byte[,], int>[17];
int rec(byte[,] arr)
{
if (arr.Length == 1) return arr[0, 0];
int opt = find(arr);
if (opt != -1) return opt;
opt = 1 << 25;
for (int i = 0; i < arr.GetLength(1); ++i)
opt = Math.Min(opt, arr[0, i] + rec(divide(arr, i)));
add(arr, opt);
return opt;
}
This chooses an element from row 0 of the current matrix and then divides the matrix and calls itself recursively to solve the submatrix. Function divide divides the current matrix according to the selected element. The sub-matrix size is then (N-1)x(N-1). Function find performs linear search in memo[n], and add adds the solution to memo[n] But this is too slow as it will compare each matrix with other.
Do you have some inhancements? Is there a faster DP algorithm? Any help is appreciated
EXAMPLE
1 2 3 4
8 7 6 5
9 11 10 12
13 14 16 15
The optimal solution: 1 + 5 + 10 + 14
Steps:
7 6 5
11 10 12
14 16 15
11 10
14 16
14
This is actually the assignment problem. It can be solved in polynomial time using the Hungarian algorithm, among other methods.