Can you suggest simpler and clearer way to write this function?
let cartesian_product sequences =
let step acc sequence = seq {
for x in acc do
for y in sequence do
yield Seq.append x [y] }
Seq.fold step (Seq.singleton Seq.empty) sequences
Less elegant, but (seems to be) faster solution:
let cartesian_product2 sequences =
let step acc sequence = seq {
for x in acc do
for y in sequence do
yield seq { yield! x ; yield y } }
Seq.fold step (Seq.singleton Seq.empty) sequences
;
> cartesian items |> Seq.length;;
Real: 00:00:00.405, CPU: 00:00:00.405, GC gen0: 37, gen1: 1, gen2: 0
val it : int = 1000000
> cartesian_product2 items |> Seq.length;;
Real: 00:00:00.228, CPU: 00:00:00.234, GC gen0: 18, gen1: 0, gen2: 0
val it : int = 1000000
I benchmarked the function Juliet linked to:
let items = List.init 6 (fun _ -> [0..9])
cart1 items |> Seq.length |> ignore
Real: 00:00:03.324, CPU: 00:00:03.322, GC gen0: 80, gen1: 0, gen2: 0
and a slightly modified (to make it an apples-to-apples comparison) version of yours:
let cartesian items =
items |> Seq.fold (fun acc s ->
seq { for x in acc do for y in s do yield x @ [y] }) (Seq.singleton [])
cartesian items |> Seq.length |> ignore
Real: 00:00:00.763, CPU: 00:00:00.780, GC gen0: 37, gen1: 2, gen2: 1
Yours is significantly faster (and causes fewer GCs). Looks to me that what you have is good.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With