HOWTO · Csharp
How to Shuffle an Array in C#
Learn to shuffle a C# array in place with Fisher–Yates, choose a suitable random source, and understand why random-key sorting is unreliable.
On this page
Shuffling rearranges the existing elements of an array into a random order; it does not add or remove values. The Fisher–Yates algorithm is the standard in-place approach: choose an index from the portion not yet fixed, swap that value into the current position, and shrink the portion. Use Random for ordinary application behavior. Use RandomNumberGenerator when unpredictability is security-sensitive, while still applying a correct shuffle algorithm.
Shuffle an Array with Fisher–Yates
Fisher–Yates walks from the final index toward the start. At position i, it chooses j uniformly from zero through i, then swaps the two values. Each iteration fixes one position and shrinks the range. With uniform bounded choices, every permutation has equal probability.
Run this complete example:
using System;
class Program
{
static void Shuffle<T>(T[] items, Random random)
{
for (int i = items.Length - 1; i > 0; i--)
{
int j = random.Next(i + 1);
(items[i], items[j]) = (items[j], items[i]);
}
}
static void Main()
{
int[] values = { 1, 2, 3, 4, 5 };
Shuffle(values, new Random());
Console.WriteLine(string.Join(", ", values));
}
}
The loop makes n - 1 swaps for an array of length n, so it runs in linear time and changes the input array itself. The final remaining element needs no choice. An array with zero or one element therefore needs no swaps and stays unchanged. Passing the Random instance into the method also lets a caller reuse one generator for multiple shuffles.
Use Random for a General-Purpose Shuffle
For games, sampling, and other non-security tasks, Random supplies the bounded values Fisher–Yates needs. random.Next(i + 1) returns an integer from zero up to, but not including, i + 1; this makes every still-available position eligible. The complete example above uses this method and preserves every input element.
Create and reuse a Random instance when an application needs several shuffles. Repeatedly constructing generators in quick succession can produce correlated sequences on older runtime versions. The result changes across runs, so do not depend on a particular order. A shuffle changes the arrangement, not the values or their multiplicities.
Use RandomNumberGenerator for a Secure Shuffle
When the order affects a security decision, use cryptographic random bytes as the source for Fisher–Yates choices. The bounded conversion must be unbiased too: taking a random integer modulo the bound can favor some results when the number of possible integers is not divisible by that bound. Rejection sampling discards the small excess range before taking the remainder.
This complete example uses RandomNumberGenerator.Create() and its byte-filling GetBytes(byte[]) API, then applies the same descending swap loop:
using System;
using System.Security.Cryptography;
class Program
{
static ulong NextBelow(RandomNumberGenerator random, ulong bound)
{
byte[] bytes = new byte[8];
ulong threshold = unchecked(0UL - bound) % bound;
ulong value;
do
{
random.GetBytes(bytes);
value = BitConverter.ToUInt64(bytes, 0);
}
while (value < threshold);
return value % bound;
}
static void Shuffle<T>(T[] items, RandomNumberGenerator random)
{
for (int i = items.Length - 1; i > 0; i--)
{
int j = (int)NextBelow(random, (ulong)i + 1);
(items[i], items[j]) = (items[j], items[i]);
}
}
static void Main()
{
int[] values = { 1, 2, 3, 4, 5 };
using (RandomNumberGenerator random = RandomNumberGenerator.Create())
{
Shuffle(values, random);
}
Console.WriteLine(string.Join(", ", values));
}
}
The threshold calculation rejects values below the largest evenly divisible portion’s boundary, avoiding modulo bias for each bound. RandomNumberGenerator makes choices harder to predict; it does not by itself make a biased algorithm uniform or make an insecure application design secure. Use it only when unpredictability matters, since it has more overhead than Random.
Why OrderBy with Random Is Not a Reliable Shuffle
Sorting elements by generated random keys is not the same operation as directly selecting and swapping from the remaining range. It performs a sort, generally requiring more work than the linear Fisher–Yates loop. Random keys can also collide, leaving the ordering of tied elements dependent on sort behavior. Such code may appear to work for a quick demonstration, but it is not the preferred way to obtain a uniform permutation. The Fisher–Yates algorithm makes the choices and their shrinking bounds explicit.
Choose the Right Approach
Use Fisher–Yates with Random for ordinary shuffling, and use the same algorithm with RandomNumberGenerator when security depends on an unpredictable order. In either case, unbiased bounded choices matter for a uniform result. Keep the generator reusable, pass the array you intend to change, and remember that each run can produce a different order. Avoid random-key sorting when you need a clear, efficient, uniform shuffle.