First part of your question is about shuffling an array. A good algorithm is the Fisher-Yates shuffle.
The next part about comparing the result to the original is a bit more vague. I assume that you want to create a random shuffle that guarantees that all elements are shuffled to a new position. E.g.
- [0, 1, 2] => [1, 2, 0] is OK but
- [0, 1, 2] => [2, 1, 0] is not OK because 1 stays in place
I have created some extensions for doing this (note that this is a generic solution with element type T
):
static class EnumerableExtensions {
static Random random = new Random();
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source) {
var list = source.ToList();
for (var k = 0; k < list.Count; k += 1) {
var j = random.Next(k, list.Count);
Swap(list, k, j);
}
return list;
}
public static IEnumerable<T> RandomizeUniquely<T>(this IEnumerable<T> source) {
while (true) {
var randomized = source.Randomize();
var isNotUnique = source
.Zip(randomized, (a, b) => Equals(a, b))
.Any(equal => equal);
if (!isNotUnique)
return randomized;
}
}
static void Swap<T>(IList<T> list, Int32 i, Int32 j) {
var temp = list[i];
list[i] = list[j];
list[j] = temp;
}
}
The Randomize
method implements the Fisher-Yates shuffle. The RandomizeUniquely
uses this method and tries to create a shuffle that satifies the condition described above. The method simply tries until a satisfactory shuffle is found. Note that this algorithm may not terminate. E.g. if the source only has one element no unique shuffle can be found. Also, if the source contains duplicates a solution may not exist.
To use the method simply call it like this:
var randomized = Enumerable.Range(1, 7).RandomizeUniquely();
The code can be improved by validating parameters and deciding how to handle the non-termination problem described above.