# Exclude int from Random.Range

I want to make a multiple(exactly 4) Random.Range(0, 45) numbers, but I don’t want them to be the same. For example if first Random.Range generate number 5, I want the other Random.Range(0, 45) to generate any number from 0 to 45 except 5.

``````    // At the top of the file

using System;
using System.Linq;
using System.Collections.Generic;

private void Start()
{
foreach(int i in RandomValues(0, 45, 4))
Debug.Log(i);
}

private int[] RandomValues(int min, int max, int count)
{
Random random = new Random();
return Enumerable
.Range(min, max)
.OrderBy( i => random.NextDouble() )
.Take(count)
.ToArray();
}
``````

Documentation:

If you want to put a collection of stuff into a random order, your best option is usually to use a Fisher-Yates Shuffle. DO NOT sort with a random comparison function! You don’t know what this will actually do (it depends on the details of how the sort is implemented), but in practice it almost always results in bias (some permutations are significantly more likely than others). It’s also inefficient: A comparison-based sort takes at least O(n log n) time, but generating a random permutation should only take O(n) time.

But Hellium’s general approach will work:

• Make a list of the things you want to randomly choose between
• Put that list in random order
• Take the first N things in the resulting list

There are other possible approaches, but that’s probably the easiest.

1 Like

+1 for the Fisher-Yates Shuffle. If you want each number to be unique but equally likely, make a list containing the digits 0-45 and shuffle it, then pick the first four.

If you want a more specialized algorithm for this specific task, you could also do something like this:

(This code uses a custom random-number-generator interface that is not included, but the algorithm should be clear.)

``````// Chooses count items at random from the enumeration and returns them in an array
// The order of selected items within the array is also random
// If the collection is smaller than count, the entire collection is returned (in random order)
public static T[] SelectRandom<T>(this IEnumerable<T> collection, IRand rand, int count = 1)
{
if (count <= 0) return new T[0];    // Optimization for trivial case

T[] keep = new T[count];
int found = 0;
foreach (T item in collection)
{
if (found < count)
{
// Take the first #count items, in case that's all there are

// Move a random item of those found so far (including the new one)
// to the end of the array, and insert the new one in its place
int r = rand.RandInt(found + 1);
keep[found++] = keep[r];
keep[r] = item;
}
else
{
// Random chance to replace one of our previously-selected elements
++found;
if (rand.RandInt(found) < count)    // probability desired/found
{
// Replace a random previously-selected element
int r = rand.RandInt(count);
keep[r] = item;
}
}
}
if (found < count)
{
// The collection was too small to get everything requested;
// Make a new, smaller array containing everything in the collection
T[] all = new T[found];
Array.Copy(keep, all, found);
return all;
}
return keep;
}
``````

This is “optimized” in the sense that it only allocates enough memory for the needed results (not the entire original collection), it doesn’t modify the original collection, and it only requires the original collection to be an IEnumerable, not necessarily a List. It’s a bit more complicated to understand, though. (And it uses more RNG invocations.)

This is a very common Q which has been asked for years, with all sorts of specifics (for example, “can’t be the same as the last one, but otherwise can repeat”). Search for things like “unity unique random numbers”.