A simple, efficient solution is this:
Say you have N elements from which to chose.
- You randomly pick an index from 0 to N-1 and remove the picked value
from the array.
- Copy the last element of the array to the
index you removed.
- Repeat steps 1-2 treating the array as if it's one element shorter, so on the second time you pick an index between 0 and N-2, then 0 and N-3 etc.
This guarantees that you can pick any K elements in exactly K iterations (so the algorithm is deterministic) and it guarantees a uniform distribution. One other benefit is that it doesn't require any additional memory allocation.