Suppose I have a sequence of numbers: {n, n+1, n+2, ... n + m}
Without storing the numbers ahead of time I want to create a function f(), which given the sequence {1,2,3
If you want a 1:1 mapping, go with Fisher-Yates as mentioned in the other answers.
If you don't care about 1:1 mapping, and you just need all of the resulting values to be from the given sequence (with the possibility of repeats), then you can use a random function with a specified range.
For example, in C++, you could use rand() in the following way -
result = rand() % (m+1) + n
So for your example,
result = rand() % 8 + 10
Would produce an integer between 10 and 17.
This question is analogous to shuffling a deck of (m + 1) cards, numbered [n, ..., n + m]. Notice that the numbering (and thus n
) is unimportant; what matters is that we can tell the cards apart. (You can simply add the n
back later if desired.)
To do what you want, you can perform a Fisher-Yates shuffle and just keep track of which indices have been selected for shuffling so far. This will allow you to avoid storing another copy of the values themselves, as requested.
There is a simple function that generates a permutation of [0..m-1]
for a given m
. Just pick a number k
, relatively prime to m
and let f(i)=(k*i) mod m
. This always generates a permutation (no repeats on 0<=i<m
). It works better if k
is larger than m
.
For example, m=20, let k=137 (Python code, %
means modulo):
>>> [(137*i) % 20 for i in range(20)]
[0, 17, 14, 11, 8, 5, 2, 19, 16, 13, 10, 7, 4, 1, 18, 15, 12, 9, 6, 3]
This is a very simple PRNG, no guarantees about its statistical properties.
add the initial values to a list.
then, use a random number to pick a new index value in the range of the list's current size.
use that index to select and then remove the number from the list.
as somebody already pointed out, this is similar to having a deck of cards, and then randomly removing one card at a time.