ORIGINAL WORDING
(SKIP TO THE UPDATE BELOW)
- Let's assume that the nelements are the integers1..n.
- Represent every k-combination in increasing order (this representation gets rid of permutations inside thek-combination.)
- Now consider the lexicographic order between k-combinations (of nelements). In other words,{i_1..i_k} < {j_1..j_k}if there exists an indextsuch that
- i_s = j_sfor all- s < tand
- i_t < j_t.
 
- If {i_1..i_k}is ak-combination, definenext{i_1..i_k}to be the next element w.r.t. the lexicographic order.
Here is how to compute next{i_1..i_k}:
- Find the largest index rsuch thati_r + 1 < i_{r+1}
- If no index satisfies this condition and i_k < n, setr := k
- If none of the above conditions can be satisfied, there is no next (and the k-combination equals{n-k+1, n-k+2,... ,n})
- If rsatisfies the first condition, setnextto be{i_1, ..., i_{r-1}, i_r + 1, i_{r+1}, ..., i_k}
- If r = k(second condition), setnext := {i_1, ..., i_{k-1}, i_k + 1}.
UPDATE (Many thanks to @rici for improving the solution)
- Let's assume that the nelements are the integers1..n.
- Represent every k-combination in increasing order (this representation gets rid of permutations inside thek-combination.)
- Now consider the lexicographic order between k-combinations (of nelements). In other words,{i_1..i_k} < {j_1..j_k}if there exists an indextsuch that
- i_s = j_sfor all- s < tand
- i_t < j_t.
 
- If {i_1..i_k}is ak-combination, definenext{i_1..i_k}to be the next element w.r.t. the lexicographic order.
- Note that with this order the smallest k-combination is{1..k}and the largest{n-k+1, n-k+2,... ,n}.
Here is how to compute next{i_1..i_k}
- Find the largest index rsuch thati_rcan be incremented by1.
- Increment the value at index rand reset the following elements with consecutive values starting ati_r + 2.
- Repeat until no position can be incremented.
More precisely:
- If i_k < n, incrementi_kby1(i.e., replacei_kwithi_k + 1)
- If i_k = n, find the largest indexrsuch thati_r + 1 < i_{r+1}. Then incrementi_rby1and reset the following positions to{i_r + 2, i_r + 3, ..., i_r + k + 1 - r}
- Repeat until you reach {n-k+1, n-k+2,... ,n}
Note the recursive character of the algorithm: every time it increments the least significant position the tail is reset to the lexicographically smallest sequence that starts with the value just incremented.
Smalltalk code
SequenceableCollection >> #nextChoiceFrom: n
    | next k r ar |
    k := self size.
    (self at: 1) = (n - k + 1) ifTrue: [^nil].
    next := self shallowCopy.
    r := (self at: k) = n
      ifTrue: [(1 to: k-1) findLast: [:i | (self at: i) + 1 < (self at: i+1)]]
      ifFalse: [k].
    ar := self at: r.
    r to: k do: [:i | 
      ar := ar + 1.
      next at: i put: ar].
    ^next