/// <summary> /// Gets an enumerator that enumerates elements of the <see cref="System.Collections.Generic.IEnumerable{T}" /> sequence in a random manner. /// </summary> /// <typeparam name="T">The type of elements in the sequence.</typeparam> /// <param name="sequence">The enumerable sequence.</param> /// <param name="algorithm">The algorithm used to prevent an element from being accessed twice.</param> /// <param name="random">A <see cref="System.Random" /> object that generates random numbers. /// If this argument is not specified, a new <see cref="System.Random" /> instance will be used.</param> /// <returns> /// An enumerator that randomly enumerates elements of the sequence. /// </returns> public static IEnumerator <T> GetRandomEnumerator <T>(this IEnumerable <T> sequence, DistinctRandomAlgorithms algorithm = DistinctRandomAlgorithms.Auto, Random random = null) { var range = sequence.Count(); var count = range; if (random == null) { random = new Random(); } switch (algorithm) { default: { var ratio = (double)count / range; if (ratio > 0.2) { goto case DistinctRandomAlgorithms.Swap; } else { goto case DistinctRandomAlgorithms.SimpleHash; } } case DistinctRandomAlgorithms.SimpleHash: { var hasheset = new HashSet <int>(); while (count != 0) { --count; int val; do { val = random.Next(0, range); }while (hasheset.Contains(val)); hasheset.Add(val); yield return(sequence.ElementAt(val)); } break; } case DistinctRandomAlgorithms.Swap: { var tempArr = new int[range]; int val; while (count != 0) { val = random.Next(0, range); --range; --count; if (tempArr[val] == 0) { yield return(sequence.ElementAt(val)); } else { yield return(sequence.ElementAt(tempArr[val])); } tempArr[val] = tempArr[range] == 0 ? range : tempArr[range]; } break; } case DistinctRandomAlgorithms.SwapHash: { var dict = new Dictionary <int, int>(); int val; while (count != 0) { val = random.Next(0, range); --range; --count; int tval1, tval2; var exist1 = dict.TryGetValue(val, out tval1); var exist2 = dict.TryGetValue(range, out tval2); if (exist1) { dict[val] = exist2 ? tval2 : range; yield return(sequence.ElementAt(tval1)); } else { dict.Add(val, exist2 ? tval2 : range); yield return(sequence.ElementAt(val)); } } break; } } }
/// <summary> /// Gets an enumerator that enumerates all elements of the array in a random manner. /// </summary> /// <typeparam name="T">The type of elements in the array.</typeparam> /// <param name="array">The array.</param> /// <param name="algorithm">The algorithm used to prevent an element from being accessed twice.</param> /// <param name="random">A <see cref="System.Random" /> object that generates random numbers. /// If this argument is not specified, a new <see cref="System.Random" /> instance will be used.</param> /// <returns> /// An enumerator that randomly enumerates elements of the array. /// </returns> public static IEnumerator <T> GetRandomEnumerator <T>(this T[] array, DistinctRandomAlgorithms algorithm = DistinctRandomAlgorithms.Auto, Random random = null) { return(GetRandomEnumerator <T>(array, array.Length, algorithm, random)); }
/// <summary> /// Gets an enumerator that enumerates all elements of the <see cref="System.Collections.Generic.IList{T}"/> in a random manner. /// </summary> /// <typeparam name="T">The type of elements in the list.</typeparam> /// <param name="array">The list.</param> /// <param name="algorithm">The algorithm used to prevent an element from being accessed twice.</param> /// <param name="random">A <see cref="System.Random" /> object that generates random numbers. /// If this argument is not specified, a new <see cref="System.Random" /> instance will be used.</param> /// <returns> /// An enumerator that randomly enumerates elements of the list. /// </returns> public static IEnumerator <T> GetRandomEnumerator <T>(this IList <T> list, DistinctRandomAlgorithms algorithm = DistinctRandomAlgorithms.Auto, Random random = null) { return(GetRandomEnumerator <T>(list, list.Count, algorithm, random)); }
/// <summary> /// Gets an enumerator that enumerates elements of the array in a random manner. /// </summary> /// <typeparam name="T">The type of elements in the array.</typeparam> /// <param name="array">The array.</param> /// <param name="count">The total number of elements the enumerator should enumerate before reset.</param> /// <param name="algorithm">The algorithm used to prevent an element from being accessed twice.</param> /// <param name="random">A <see cref="System.Random" /> object that generates random numbers. /// If this argument is not specified, a new <see cref="System.Random" /> instance will be used.</param> /// <returns>An enumerator that randomly enumerates elements of the array.</returns> public static IEnumerator <T> GetRandomEnumerator <T>(this T[] array, int count, DistinctRandomAlgorithms algorithm = DistinctRandomAlgorithms.Auto, Random random = null) { var range = array.Length; if (random == null) { random = new Random(); } switch (algorithm) { default: { var ratio = (double)count / range; if (ratio > 0.2) { goto case DistinctRandomAlgorithms.Swap; } else { goto case DistinctRandomAlgorithms.SimpleHash; } } case DistinctRandomAlgorithms.SimpleHash: { var hasheset = new HashSet <int>(); while (count != 0) { --count; int val; do { val = random.Next(0, range); }while (hasheset.Contains(val)); hasheset.Add(val); yield return(array[val]); } break; } case DistinctRandomAlgorithms.Swap: { var tempArr = new int[range]; int val; var length2 = count; //max is used to store "length" here while (count != 0) { val = random.Next(0, range); --range; --count; if (tempArr[val] == 0) { yield return(array[val]); } else { yield return(array[tempArr[val]]); } tempArr[val] = tempArr[range] == 0 ? range : tempArr[range]; } break; } case DistinctRandomAlgorithms.SwapHash: { var dict = new Dictionary <int, int>(); int val; while (count != 0) { val = random.Next(0, range); --range; --count; int tval1, tval2; var exist1 = dict.TryGetValue(val, out tval1); var exist2 = dict.TryGetValue(range, out tval2); if (exist1) { dict[val] = exist2 ? tval2 : range; yield return(array[tval1]); } else { dict.Add(val, exist2 ? tval2 : range); yield return(array[val]); } } break; } } }