/// <summary> /// Get a random subset of the specified size from the provided List. /// </summary> public static IList <T> RandomSubset <T>(this IList <T> list, int n, System.Random rng = null) { if (list.Count < n) { throw new ArgumentOutOfRangeException($"Can't select a random subset of {n} items from a list of {list.Count} items."); } if (rng == null) { rng = _rng; } IList <int> indices = rng.Distinct(n, 0, list.Count); List <T> output = new List <T>(n); foreach (int index in indices) { output.Add(list[index]); } return(output); }
/// <summary> /// Generate N random positive (optionally including 0) integers that sum to the specified /// total. /// </summary> public static IList <int> SumTo( this System.Random rng, int n, int sum, bool allowZero = false ) { if (n <= 0 || sum <= 0) { throw new ArgumentException($"Can't generate {n} numbers that sum to {sum}."); } if (!allowZero && n > sum) { throw new ArgumentException($"Can't generate {n} non-zero numbers that sum to {sum}."); } // Generate a list of N-1 random numbers between 0 and sum, which will act as // partition points between the output random numbers. IList <int> divisions = allowZero ? rng.Many(n - 1, 0, sum, true) : rng.Distinct(n - 1, 1, sum, true); // Add each partition width to the list of output numbers. List <int> output = new List <int>(); int lastDivision = 0; for (int i = 0; i < divisions.Count; ++i) { output.Add(divisions[i] - lastDivision); lastDivision = divisions[i]; } output.Add(sum - lastDivision); return(output); }