C
C#2y ago
!Scofield

❔ Random problem

When choosing a random number in c#, I don't want the same number to come across again, how can I do it?
40 Replies
Mayor McCheese
Do you mean 1, 2, 3, 4 is okay; But 1, 2, 3, 4, 1 is not okay?
mtreit
mtreit2y ago
Yes, define your exact requirements. How many random numbers do you expect to generate and does it matter what range of values they fall into? There are probably several ways of solving this depending on your exact needs.
xdd
xdd2y ago
List<int> list = new List<int>();
Random rnd = new Random();

const int randmomNumbersAmount = 10;
const int randomLeftBorder = 0, randomRightBorder = 10;

while(list.Count < randmomNumbersAmount)
{
int number = rnd.Next(randomLeftBorder, randomRightBorder);
if (!list.Contains(number))
list.Add(number);
}
List<int> list = new List<int>();
Random rnd = new Random();

const int randmomNumbersAmount = 10;
const int randomLeftBorder = 0, randomRightBorder = 10;

while(list.Count < randmomNumbersAmount)
{
int number = rnd.Next(randomLeftBorder, randomRightBorder);
if (!list.Contains(number))
list.Add(number);
}
You can try something like this if I understand correctly what you want.
mtreit
mtreit2y ago
A HashSet would be a much better data structure than a List for keeping track of the values that have already been used
Mayor McCheese
That's what I was thinking but I didn't want to type it out on my phone without being sure of reqs
Google
Google2y ago
Fisher-Yates shuffle and call it a day
hiyosilver
hiyosilver2y ago
How does shuffling help?
Mayor McCheese
Doesn't that require a known set of values first?
Google
Google2y ago
1..int.maxvalue
!Scofield
!ScofieldOP2y ago
yes i want this I'm sorry for the late reply i will try thank you all in advance
Mayor McCheese
like @mtreit said, a HashSet will better handle the case of I've already got it
mtreit
mtreit2y ago
How many random numbers do you need to generate? Because by the pigeon hole principle you will eventually have to repeat.
!Scofield
!ScofieldOP2y ago
estimated 45-50
mtreit
mtreit2y ago
Do they need to be within a certain range?
!Scofield
!ScofieldOP2y ago
OK, let it be repeated, but for example, coming back to 5 after 5 is a problem for me. yes
mtreit
mtreit2y ago
What's the range?
Mayor McCheese
1-2
mtreit
mtreit2y ago
sus
Mayor McCheese
There's an infinite set of numbers between 1 and 2 3.14 to 3.15 is interesting too
!Scofield
!ScofieldOP2y ago
I don't understand much from c#. I'm working on Unity and I want to turn off the random number doubles in my game. It doesn't feel right for me to share because there are Unity codes rndm = Random.Range(1, 45);
mtreit
mtreit2y ago
So you want to hand out 50 random numbers in the range of 1 to 45 without duplicates?
!Scofield
!ScofieldOP2y ago
I can explain like this. 34,23,43,43 I don't want the same number to appear side by side again. I want the incoming number to be less likely to come back Im really sorry if I cant explain but my english is not that clear or if a number comes up once, number must wait for the other 50 numbers to finish before it comes back
mtreit
mtreit2y ago
I think you can achieve this by simply generating a pool of numbers, shuffling them, and then keeping a pointer into that shuffled set and using that to hand out the next value. Do you want to hand out more numbers than is in the range (like the example I gave?) Because that's obviously a problem since duplicates are guaranteed 🙂
!Scofield
!ScofieldOP2y ago
Yes it makes sense. I will do it. Thanks for your help No, I know I can't explain my problem fully, but I think I'd better do what you just said.
mtreit
mtreit2y ago
I'm not sure it's the best approach, you could still end up with duplicates next to each other in the sequence. @!Scofield here is a completely brute force way to do this that will definitely work. It has theoretical performance problems if the same number that has already been sent keeps getting generated, but in your example it's probably fine.
xdd
xdd2y ago
like, 34, 23, 43, 20, 43 is ok?
mtreit
mtreit2y ago
using System;
using System.Collections.Generic;

namespace Test
{
class TestClass
{
static void Main()
{
var gen = new RandomGenerator(1, 45);
for (int i = 0; i < 100; i++)
{
Console.Write(gen.Next());
Console.Write(" ");
}
}
}

internal class RandomGenerator
{
int _numberSeen;
int _minVal;
int _maxVal;
HashSet<int> _previous;

public RandomGenerator(int minVal, int maxValInclusive)
{
_previous = new HashSet<int>();
_minVal = minVal;
_maxVal = maxValInclusive;
}

public int Next()
{
while (true)
{
var candidate = Random.Shared.Next(_minVal, _maxVal + 1);
var maxAllowed = _maxVal + 1 - _minVal;

if (_numberSeen >= maxAllowed)
{
_numberSeen = 0;
_previous.Clear();
Console.WriteLine();
}

if (!_previous.Contains(candidate))
{
_previous.Add(candidate);
_numberSeen++;
return candidate;
}
}
}
}
}
using System;
using System.Collections.Generic;

namespace Test
{
class TestClass
{
static void Main()
{
var gen = new RandomGenerator(1, 45);
for (int i = 0; i < 100; i++)
{
Console.Write(gen.Next());
Console.Write(" ");
}
}
}

internal class RandomGenerator
{
int _numberSeen;
int _minVal;
int _maxVal;
HashSet<int> _previous;

public RandomGenerator(int minVal, int maxValInclusive)
{
_previous = new HashSet<int>();
_minVal = minVal;
_maxVal = maxValInclusive;
}

public int Next()
{
while (true)
{
var candidate = Random.Shared.Next(_minVal, _maxVal + 1);
var maxAllowed = _maxVal + 1 - _minVal;

if (_numberSeen >= maxAllowed)
{
_numberSeen = 0;
_previous.Clear();
Console.WriteLine();
}

if (!_previous.Contains(candidate))
{
_previous.Add(candidate);
_numberSeen++;
return candidate;
}
}
}
}
}
Sample output:
44 6 31 5 19 29 17 43 35 34 2 1 39 23 27 13 11 45 40 26 37 22 36 18 24 16 20 7 32 28 12 25 15 8 10 30 41 42 14 3 33 4 38 9 21
4 34 13 1 43 19 42 39 26 32 5 2 15 28 33 44 38 21 35 41 10 25 3 18 9 37 36 45 27 29 11 7 12 17 24 8 23 20 16 30 14 22 31 40 6
44 28 20 26 25 43 6 34 33 39
44 6 31 5 19 29 17 43 35 34 2 1 39 23 27 13 11 45 40 26 37 22 36 18 24 16 20 7 32 28 12 25 15 8 10 30 41 42 14 3 33 4 38 9 21
4 34 13 1 43 19 42 39 26 32 5 2 15 28 33 44 38 21 35 41 10 25 3 18 9 37 36 45 27 29 11 7 12 17 24 8 23 20 16 30 14 22 31 40 6
44 28 20 26 25 43 6 34 33 39
No number will ever repeat until all possible values have been sent Performance of this seems totally fine after testing, I think it's a much better solution than my original suggestion.
Google
Google2y ago
Fisher-Yates shuffle wins!
Mayor McCheese
Fyaseh-Resti Shuffle
mtreit
mtreit2y ago
No, it was rejected
!Scofield
!ScofieldOP2y ago
Im really grateful, sorry if I stole your time
mtreit
mtreit2y ago
Not at all, it was a fun problem to think about.
mtreit
mtreit2y ago
Actually I guess if you re-shuffled after the entire sequence has been produced you would avoid repeating the same exact number sequence over and over again.
Google
Google2y ago
Yep. It's deterministic.
mtreit
mtreit2y ago
using System;

namespace Test
{
class TestClass
{
static void Main()
{
var gen = new RandomGenerator(1, 10);
for (int i = 0; i < 100; i++)
{
Console.Write(gen.Next());
Console.Write(" ");
}
}
}

internal class RandomGenerator
{
int _numberSeen;
int _minVal;
int _maxVal;
int[] _values;

public RandomGenerator(int minVal, int maxValInclusive)
{
_minVal = minVal;
_maxVal = maxValInclusive;
var maxAllowed = _maxVal + 1 - _minVal;
_values = new int[maxAllowed];
for (int i = minVal; i < _values.Length; i++)
{
_values[i] = i;
}

FisherYates(_values);
}

public int Next()
{
if (_numberSeen == _values.Length)
{
FisherYates(_values);
Console.WriteLine();
_numberSeen = 0;
}

return _values[_numberSeen++];
}

public void FisherYates<T>(T[] values)
{
for (int i = values.Length - 1; i >= 0; --i)
{
int n = Random.Shared.Next(i, values.Length);
Swap(i, n);
}

void Swap(int x, int y)
{
T tmp = values[x];
values[x] = values[y];
values[y] = tmp;
}
}
}
}
using System;

namespace Test
{
class TestClass
{
static void Main()
{
var gen = new RandomGenerator(1, 10);
for (int i = 0; i < 100; i++)
{
Console.Write(gen.Next());
Console.Write(" ");
}
}
}

internal class RandomGenerator
{
int _numberSeen;
int _minVal;
int _maxVal;
int[] _values;

public RandomGenerator(int minVal, int maxValInclusive)
{
_minVal = minVal;
_maxVal = maxValInclusive;
var maxAllowed = _maxVal + 1 - _minVal;
_values = new int[maxAllowed];
for (int i = minVal; i < _values.Length; i++)
{
_values[i] = i;
}

FisherYates(_values);
}

public int Next()
{
if (_numberSeen == _values.Length)
{
FisherYates(_values);
Console.WriteLine();
_numberSeen = 0;
}

return _values[_numberSeen++];
}

public void FisherYates<T>(T[] values)
{
for (int i = values.Length - 1; i >= 0; --i)
{
int n = Random.Shared.Next(i, values.Length);
Swap(i, n);
}

void Swap(int x, int y)
{
T tmp = values[x];
values[x] = values[y];
values[y] = tmp;
}
}
}
}
Here's the same program but using Fisher-Yates
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.

Did you find this page helpful?