Подключите снова с помощью решения Haskell (просто работать с отложенными списками проще, поскольку они встроены):
combinations 0 _ = [[]]
combinations k [] = []
combinations k (x:xs) = map (x:) (combinations (k-1) xs) ++ combinations k xs
Первые два случая следуют из свойств биномиальных коэффициентов и, более конкретно: n choose 0 = 1
для всех n
, включая n=0
(именно поэтому он первым обрабатывает случай 0 choose 0
) , Другой - 0 choose k = 0
. Третье уравнение является точным переводом рекурсивного определения комбинаций.
К сожалению, когда вы применяете его к бесконечному списку, он возвращает тривиальное решение:
> 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:
Итак, мы действительно хотим пройти каждую комбинацию за конечное число шагов. В вышеприведенной версии мы, очевидно, используем только выражение слева от ++
, которое генерирует только комбинации, начинающиеся с 1. Мы можем обойти эту проблему, определив интересную функцию архивирования списка, которая формирует список, чередуя выбор заголовка каждого из списков аргументов (важно не быть строгими во втором аргументе):
merge [] ys = ys
merge (x:xs) ys = x:merge ys xs
и используйте его вместо ++
:
combinations k (x:xs) = map (x:) (combinations (k-1) xs) `merge` combinations k xs
давайте посмотрим:
> 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
Все 10 choose 3
комбинации есть!