/// <summary> /// Returns a random subset of an array with a supplied number of /// elements (subsetCount). The elements in the subset are in the /// same order as in the original array. O(count). /// NOTE: this method needs to generate one random number for each /// element of the original array. If subsetCount is significantly /// smaller than count, it is more efficient to use /// <see cref="CreateSmallRandomSubsetIndexArray"/> or /// <see cref="CreateSmallRandomSubsetIndexArrayLong"/> or /// <see cref="CreateSmallRandomOrderedSubsetIndexArray"/> or /// <see cref="CreateSmallRandomOrderedSubsetIndexArrayLong"/>. /// </summary> public static T[] CreateRandomSubsetOfSize <T>( this T[] array, long subsetCount, IRandomUniform rnd = null) { if (rnd == null) { rnd = new RandomSystem(); } long count = array.LongLength; if (!(subsetCount >= 0 && subsetCount <= count)) { throw new ArgumentOutOfRangeException(nameof(subsetCount)); } var subset = new T[subsetCount]; long si = 0; for (int ai = 0; ai < count && si < subsetCount; ai++) { var p = (double)(subsetCount - si) / (double)(count - ai); if (rnd.UniformDouble() <= p) { subset[si++] = array[ai]; } } return(subset); }
/// <summary> /// Returns a random subset of the enumeration with a supplied number of /// elements (subsetCount). The elements in the subset are in the /// same order as in the input. O(count). /// NOTE: The number of elements of the Enumerable need to be calculated, in case of true enumerations /// the implementation of .Count() results in a second evaluation of the enumerable. /// </summary> public static T[] CreateRandomSubsetOfSize <T>( this IEnumerable <T> input, long subsetCount, IRandomUniform rnd = null) { if (rnd == null) { rnd = new RandomSystem(); } long count = input.Count(); if (!(subsetCount >= 0 && subsetCount <= count)) { throw new ArgumentOutOfRangeException(nameof(subsetCount)); } var subset = new T[subsetCount]; long si = 0, ai = 0; foreach (var a in input) { if (ai < count && si < subsetCount) { var p = (double)(subsetCount - si) / (double)(count - ai++); if (rnd.UniformDouble() <= p) { subset[si++] = a; } } else { break; } } return(subset); }
/// <summary> /// Enumerates elements in random order. /// </summary> public static IEnumerable <T> RandomOrder <T>(this IEnumerable <T> self, IRandomUniform rnd = null) { var tmp = self.ToArray(); if (rnd == null) { rnd = new RandomSystem(); } var perm = rnd.CreatePermutationArray(tmp.Length); return(perm.Select(index => tmp[index])); }
/// <summary> /// Yields each element with propability p. /// </summary> public static IEnumerable <R> TakeRandomly <T, R>(this IEnumerable <T> self, Func <T, R> selector, double p, IRandomUniform random = null) { if (self == null) { throw new ArgumentNullException(); } if (p < 0 || p > 1) { throw new ArgumentOutOfRangeException(); } if (random == null) { random = new RandomSystem(); } foreach (var s in self) { if (random.UniformDouble() <= p) { yield return(selector(s)); } } }