F#排列

Ale*_*dar 10 f#

我需要在给定列表上生成排列.我设法做到这一点

let rec Permute (final, arr) = 
    if List.length arr > 0 then
        for x in arr do
            let n_final = final @ [x]
            let rest = arr |> List.filter (fun a -> not (x = a))
            Permute (n_final, rest)
    else
        printfn "%A" final

let DoPermute lst  = 
    Permute ([], lst)

DoPermute lst
Run Code Online (Sandbox Code Playgroud)

这段代码存在明显的问题.例如,列表元素必须是唯一的.而且,这与我在任何其他语言中生成直接实现时使用的方法相同.有没有更好的方法在F#中实现它.

谢谢!

Jon*_*rop 29

这是我在F#科学家的书中给出的解决方案(第166-167页):

let rec distribute e = function
  | [] -> [[e]]
  | x::xs' as xs -> (e::xs)::[for xs in distribute e xs' -> x::xs]

let rec permute = function
  | [] -> [[]]
  | e::xs -> List.collect (distribute e) (permute xs)
Run Code Online (Sandbox Code Playgroud)


cfe*_*ern 7

对于小列表的排列,我使用以下代码:

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)
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:函数"distrib"将给定元素分布在列表中的所有位置,例如:

distrib 10 [1;2;3] --> [[10;1;2;3];[1;10;2;3];[1;2;10;3];[1;2;3;10]]
Run Code Online (Sandbox Code Playgroud)

函数perms工作(递归地)如下:将列表的头部分布在其尾部的所有排列上.

对于大型列表,distrib函数会变慢,因为它大量使用@运算符,但对于合理长度(<= 10)的列表,上面的代码工作正常.

一个警告:如果您的列表包含重复项,结果将包含相同的排列.例如:

perms [1;1;3] = [[1;1;3]; [1;1;3]; [1;3;1]; [1;3;1]; [3;1;1]; [3;1;1]]
Run Code Online (Sandbox Code Playgroud)

这段代码的好处是它返回一系列排列,而不是一次性生成所有排列.

当然,使用命令式基于阵列的算法生成排列(更快)会更快,但是这种算法在大多数情况下都很适合我.


fmr*_*fmr 5

这是另一个基于序列的版本,希望比投票的答案更具可读性。这个版本在逻辑上与 Jon 的版本类似,但使用计算表达式而不是列表。第一个函数计算在列表 l 中插入元素 x 的所有方法。第二个函数计算排列。您应该能够在更大的列表上使用它(例如,对一组输入的所有排列进行强力搜索)。

let rec inserts x l =
  seq { match l with
        | [] -> yield [x]
        | y::rest ->
            yield x::l
            for i in inserts x rest do
              yield y::i
      }

let rec permutations l =
  seq { match l with
        | [] -> yield []
        | x::rest ->
            for p in permutations rest do
              yield! inserts x p
      }
Run Code Online (Sandbox Code Playgroud)