open System.Collections.Generic
| NonEmpty of 'T * 'T ImmutableStack
interface 'T IEnumerable with
member this.GetEnumerator () =
(Seq.unfold (function Empty -> None | NonEmpty (head, tail) -> Some (head, tail)) this).GetEnumerator ()
member this.GetEnumerator () = (this :> 'T IEnumerable).GetEnumerator () :?> IEnumerator
let rec private impl (n: int, k: int): bool ImmutableStack seq = seq {
if k = 0 then yield Empty
else for r in impl (n - 1, k - 1) -> NonEmpty (true, r)
for r in impl (n - 1, k) -> NonEmpty (false, r)
let private zipWhere (items: 'T seq, selectors: bool seq): 'T seq = seq {
use e1 = items.GetEnumerator ()
use e2 = selectors.GetEnumerator ()
while e1.MoveNext () && e2.MoveNext () do
if e2.Current then yield e1.Current
let combinations (items: 'T seq, k: int): 'T seq seq = seq {
if k < 0 then invalidOp ""
for combination in impl (Seq.length items, k) ->
zipWhere (items, combination)
let rec private impl = function
for c in impl (xs, k - 1) -> x :: c
let combinations k items =
if k < 0 then invalidOp ""
impl (Seq.toList items, k)
let private printCombination = Seq.map string >> String.concat "," >> printfn "%s"
let data, size = { 50 .. 10 .. 90 }, 3
CSharp.combinations (data, size)
|> Seq.iter printCombination
FSharp.combinations size data
|> Seq.iter printCombination