How to retrieve k random numbers from an array of unknown size at compile time in C#

1 Answer

0 votes
using System;

namespace RandomSamplingDemo
{
    internal static class Program
    {
        /*
         * GetRandomSample
         *
         * Returns k unique random elements from the source array.
         *
         * Parameters:
         *   source : Input array. Its size is determined at runtime.
         *   k      : Number of random elements to retrieve.
         *
         * Returns:
         *   An array containing k randomly selected elements.
         *
         * Approach:
         *   We create a copy of the original array and perform a
         *   partial Fisher-Yates shuffle.
         *
         *   During iteration i:
         *     1. Select a random position between i and the end.
         *     2. Swap the elements.
         *     3. Position i now contains one randomly selected item.
         *
         *   After k iterations, the first k elements form a valid
         *   random sample without duplicates.
         *
         * Benefits:
         *   - No duplicate selections.
         *   - Original array is not modified.
         *   - Uniform random distribution.
         *   - Simple and efficient.
         */
        public static int[] GetRandomSample(int[] source, int k)
        {
            if (source == null) {
                throw new ArgumentNullException(nameof(source));
            }

            if (k < 0 || k > source.Length) {
                throw new ArgumentOutOfRangeException(
                    nameof(k),
                    "k must be between 0 and the number of elements.");
            }

            // Make a copy so the caller's array remains unchanged.
            int[] workingCopy = (int[])source.Clone();

            // Use a single Random instance.
            Random random = new Random();

            // Partial Fisher-Yates shuffle.
            for (int i = 0; i < k; i++)
            {
                int randomIndex = random.Next(i, workingCopy.Length);

                (workingCopy[i], workingCopy[randomIndex]) =
                    (workingCopy[randomIndex], workingCopy[i]);
            }

            int[] result = new int[k];

            Array.Copy(
                workingCopy,
                sourceIndex: 0,
                destinationArray: result,
                destinationIndex: 0,
                length: k);

            return result;
        }

        private static void Main()
        {
            try
            {
                // Example array.
                // The size is known only at runtime.
                int[] numbers =
                {
                    10, 20, 30, 40, 50,
                    60, 70, 80, 90, 100
                };

                int k = 4;

                int[] sample = GetRandomSample(numbers, k);

                Console.WriteLine("Original array:");
                Console.WriteLine(string.Join(", ", numbers));

                Console.WriteLine();
                Console.WriteLine($"Random sample ({k} elements):");
                Console.WriteLine(string.Join(", ", sample));
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }
    }
}



/*
run:

Original array:
10, 20, 30, 40, 50, 60, 70, 80, 90, 100

Random sample (4 elements):
10, 60, 90, 40

*/

 



answered Oct 2 by avibootz
...