Plugging in again with a Haskell solution (it's just easier to work with lazy lists since they are built-in):
combinations 0 _ = [[]]
combinations k [] = []
combinations k (x:xs) = map (x:) (combinations (k-1) xs) ++ combinations k xs
The first two cases follow from the properties of binomial coefficients and more specifically: n choose 0 = 1
for all n
including n=0
(that's why it is first to handle the case 0 choose 0
). The other one is 0 choose k = 0
. The third equation is exact translation of the recursive definition of combinations.
Unfortunately when you apply it to an infinite list it returns a trivial solution:
> take 10 $ combinations 3 [1..]
[[1,2,3],[1,2,4],[1,2,5],[1,2,6],[1,2,7],[1,2,8],[1,2,9],[1,2,10],[1,2,11],[1,2,12]]
EDIT:
OK, so we really want to go trough each combination in a finite number of steps. With the above version we are obviously using only the expression to the left of ++
which generates only combinations starting with 1. We can work around this problem by defining an interesting list zipping function which builds a list by alternately picking the head of each of its argument lists (it's important to be non-strict in the second argument):
merge [] ys = ys
merge (x:xs) ys = x:merge ys xs
and use it instead of ++
:
combinations k (x:xs) = map (x:) (combinations (k-1) xs) `merge` combinations k xs
lets see:
> let comb_10_3 = combinations 3 [1..10]
> let comb_inf_3 = combinations 3 [1..]
> take 10 comb_inf_3
[[1,2,3],[2,3,4],[1,3,4],[3,4,5],[1,2,4],[2,4,5],[1,4,5],[4,5,6],[1,2,5],[2,3,5]]
> comb_10_3 `intersect` comb_inf_3 == comb_10_3
True
> last $ combinations 3 [1..10]
[6,8,10]
> elemIndex [6,8,10] $ combinations 3 [1..]
Just 351
All 10 choose 3
combinations are there!