I\'ve recently written the following combinations and permutations functions for an F# project, but I\'m quite aware they\'re far from optimised.
/// Rotates
I noticed that your updated getPerms function contains duplicates. Here's my crack at a dupe-free version. Hopefully the comments speak for themselves. The hardest part was writing an efficient distrib
function, because the concatenation operator has to be used somewhere. Luckily it's only used on small sublists, so the performance remains reasonable. My getAllPerms code below generates all permutations of [1..9] in around a quarter of a second, all 10-element permutations in around 2.5 seconds.
Edit: funny, I didn't look at Tomas' code, but his combinations function and my picks function are nearly identical.
// All ordered picks {x_i1, x_i2, .. , x_ik} of k out of n elements {x_1,..,x_n}
// where i1 < i2 < .. < ik
let picks n L =
let rec aux nleft acc L = seq {
match nleft,L with
| 0,_ -> yield acc
| _,[] -> ()
| nleft,h::t -> yield! aux (nleft-1) (h::acc) t
yield! aux nleft acc t }
aux n [] L
// Distribute an element y over a list:
// {x1,..,xn} --> {y,x1,..,xn}, {x1,y,x2,..,xn}, .. , {x1,..,xn,y}
let distrib y L =
let rec aux pre post = seq {
match post with
| [] -> yield (L @ [y])
| h::t -> yield (pre @ y::post)
yield! aux (pre @ [h]) t }
aux [] L
// All permutations of a single list = the head of a list distributed
// over all permutations of its tail
let rec getAllPerms = function
| [] -> Seq.singleton []
| h::t -> getAllPerms t |> Seq.collect (distrib h)
// All k-element permutations out of n elements =
// all permutations of all ordered picks of length k combined
let getPerms2 n lst = picks n lst |> Seq.collect getAllPerms
Edit: more code in response to comments
// Generates the cartesian outer product of a list of sequences LL
let rec outerProduct = function
| [] -> Seq.singleton []
| L::Ls -> L |> Seq.collect (fun x ->
outerProduct Ls |> Seq.map (fun L -> x::L))
// Generates all n-element combination from a list L
let getPermsWithRep2 n L =
List.replicate n L |> outerProduct