You are very close to understanding how such a shuffle works. In your second case
pupils.OrderBy(x => x.Age);
Comparer<int>.Default (faces are sorted by their Age , simple).
In your first case, Comparer<Guid>.Default .
How it works?
Each time you do Guid.NewGuid() (presumably), a different / original / non-duplicated Guid . Now when you do
var randomNumbers = Enumerable.Range(0, 100).OrderBy(x => Guid.NewGuid());
numbers are sorted based on the created Guides.
Now what are guides?
They are 128-bit integers represented in hexadecimal. Since 2 ^ 128 is such a large number, the possibilities of generating two Guides are very rare / almost impossible. Because the Guides exhibit some kind of randomness, the ordering will also be random.
How do two guides compare in order?
You can confirm this based on a trivial experiment. At:
var guids = Enumerable.Range(0, 10).Select((x, i) => { Guid guid = Guid.NewGuid(); return new { Guid = guid, NumberRepresentation = new BigInteger(guid.ToByteArray()), OriginalIndex = i }; }).ToArray(); var guidsOrderedByTheirNumberRepresentation = guids.OrderBy(x => x.NumberRepresentation).ToArray(); var guidsOrderedAsString = guids.OrderBy(x => x.Guid.ToString()).ToArray(); var randomNumbers = Enumerable.Range(0, 10).OrderBy(x => guids[x].Guid).ToArray();
So, Comparer<Guid>.Default based on the string representation of guid.
Besides
You must use Fisher-Yates when shuffling speed. May be
public static IEnumerable<T> Shuffle<T>(this IList<T> lst) { Random rnd = new Random(); for (int i = lst.Count - 1; i >= 0; i--) { int j = rnd.Next(i + 1); yield return lst[j]; lst[j] = lst[i]; } }
Or for brevity it could be simple (which could be even faster than the Guid approach)
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> lst) { Random rnd = new Random(); return lst.OrderBy(x => rnd.Next()); }