Im doing a simple Quiz game and I needed a way to get unique random numbers, so I can play the questions in a random order without repeating them. Found the code.
private int maxNumbers = 6;
private List<int> uniqueNumbers;
private List<int> finishedList;
void Start ()
{
uniqueNumbers = new List<int>();
finishedList = new List<int>();
GenerateRandomList();
}
public void GenerateRandomList()
{
for (int i = 0; i < maxNumbers; i++)
{
uniqueNumbers.Add(i);
}
for (int i = 0; i < maxNumbers; i++)
{
int ranNum = uniqueNumbers[Random.Range(0, uniqueNumbers.Count)];
finishedList.Add(ranNum);
uniqueNumbers.Remove(ranNum);
}
//Just to see them in the console
foreach (int data in finishedList)
{
Debug.Log(data);
}
}
The problem here is that the random numbers appear all in once. I need one number at a time and the next randomization just start when I want to, by pressing a button or whatever.
But that’s just the way I feel I can do. For sure there’s a way to do with the numbers all in once in the list.
int PickAndRemoveOneRandom()
{
int randomNum = Random.Range(0, myList.Count); //Pick one random number based on total numbers.
int theNumber = myList[randomNum]; //store the number
myList.Remove(randomNum); //Remove number so it cant be used again.
return theNumber; //return the number
}
Then use the method in your code
int theNumber = PickAndRemoveOneRandom();
Or onClick event on a Unity UI Button → PickAndRemoveOneRandom() and add your " //do stuff code" in the function instead of returning an int
Options:
You could pass the list as parameter: void myMethod(List myList) { }
You could make this support generic types (return & remove ANY type from any List, insuring uniqueness
Keep used numbers in a second List (just add one line before return. usedNumberList.Add(theNumber)
This is preety old but I was looking for an answer to the same question and I ended writing an algorithm my self. Seems to work preety well.
//"from" and "to" are inclusive
public List<int> GenerateRandomIntegerList(int from, int to)
{
List<int> numbersDone = new List<int>();
while (true)
{
int i = Random.Range(from, to + 1);
bool isNew = true;
foreach (int num in numbersDone)
{
if (num == i)
{
isNew = false;
}
}
if(isNew)
{
numbersDone.Add(i);
if(numbersDone.Count == to + 1)
break;
}
}
return numbersDone;
}
Just for the sake of completeness, since all the other answers seem to be pretty good already, but I usually do this using a Set structure (HashSets of int in particular).
–
If you know your numbers beforehand: Here’s some pseudo-code:
- Let there be an empty Set of type Set of Integers called 'SortitionSet'
- Let there be an Integer Array containing the numbers we want to Sortition called 'IntegersArray'
Generate the SortitionSet:
While(Length of IntegersArray > 0)
Let there be an auxiliary variable which receives a the resulting element from the deletion of the first element of the array called 'aux'
Try to insert aux into SortitionSet (It should return false in case of a repeated number)
In case the insertion was successful continue, otherwise throw exception
Return SortitionSet
Give a Random Number from the Set by Removing it:
Return SortitionSet.Remove(Random Index)
</end>
–
If you don’t know your numbers beforehand:
Here’s some pseudo-code:
<begin/>
- Let there be an empty Set of type Set of Integers called 'SortitionSet'
- Let there be a positive Integer number greater than zero called 'AmountOfNumbersToGenerate'
Then:
While(AmountOfNumbersToGenerate > 0)
Let there be an auxiliary variable which receives a randomly generated number called 'aux'
Try to insert aux into SortitionSet (It should return false in case of a repeated number)
In case the insertion was successful reduce AmountOfNumbersToGenerate by 1
Return SortitionSet
</end>