To rearrange small lists, I use the following code:
let distrib e L = let rec aux pre post = seq { match post with | [] -> yield (L @ [e]) | h::t -> yield (List.rev pre @ [e] @ post) yield! aux (h::pre) t } aux [] L let rec perms = function | [] -> Seq.singleton [] | h::t -> Seq.collect (distrib h) (perms t)
It works as follows: the "distrib" function distributes the given element among all positions in the list, for example:
distrib 10 [1;2;3] --> [[10;1;2;3];[1;10;2;3];[1;2;10;3];[1;2;3;10]]
The perms function works (recursively) as follows: distributes the list head over all permutations of its tail.
The distribution function will be slow for large lists, since it uses the @ operator a lot, but for lists of reasonable length (<= 10), the code above works fine.
One warning: if your list contains duplicates, the result will contain identical permutations. For example:
perms [1;1;3] = [[1;1;3]; [1;1;3]; [1;3;1]; [1;3;1]; [3;1;1]; [3;1;1]]
The best part about this code is that it returns a sequence of permutations, rather than generating them all at once.
Of course, generating permutations with an imperative array-based algorithm will be (much) faster, but in most cases this algorithm has proven itself to me.
cfern Oct 06 '09 at 15:09 2009-10-06 15:09
source share