gpt4 book ai didi

f# - F# 中的组合和排列

转载 作者:行者123 更新时间:2023-12-04 01:40:32 24 4
gpt4 key购买 nike

我最近为 F# 项目编写了以下组合和排列函数,但我很清楚它们远未得到优化。

/// Rotates a list by one place forward.
let rotate lst =
List.tail lst @ [List.head lst]

/// Gets all rotations of a list.
let getRotations lst =
let rec getAll lst i = if i = 0 then [] else lst :: (getAll (rotate lst) (i - 1))
getAll lst (List.length lst)

/// Gets all permutations (without repetition) of specified length from a list.
let rec getPerms n lst =
match n, lst with
| 0, _ -> seq [[]]
| _, [] -> seq []
| k, _ -> lst |> getRotations |> Seq.collect (fun r -> Seq.map ((@) [List.head r]) (getPerms (k - 1) (List.tail r)))

/// Gets all permutations (with repetition) of specified length from a list.
let rec getPermsWithRep n lst =
match n, lst with
| 0, _ -> seq [[]]
| _, [] -> seq []
| k, _ -> lst |> Seq.collect (fun x -> Seq.map ((@) [x]) (getPermsWithRep (k - 1) lst))
// equivalent: | k, _ -> lst |> getRotations |> Seq.collect (fun r -> List.map ((@) [List.head r]) (getPermsWithRep (k - 1) r))

/// Gets all combinations (without repetition) of specified length from a list.
let rec getCombs n lst =
match n, lst with
| 0, _ -> seq [[]]
| _, [] -> seq []
| k, (x :: xs) -> Seq.append (Seq.map ((@) [x]) (getCombs (k - 1) xs)) (getCombs k xs)

/// Gets all combinations (with repetition) of specified length from a list.
let rec getCombsWithRep n lst =
match n, lst with
| 0, _ -> seq [[]]
| _, [] -> seq []
| k, (x :: xs) -> Seq.append (Seq.map ((@) [x]) (getCombsWithRep (k - 1) lst)) (getCombsWithRep k xs)

有没有人对如何加速这些功能(算法)有任何建议?我对如何改进排列(有和没有重复)的排列特别感兴趣。回想起来,涉及列表轮换的业务对我来说似乎不太有效。

更新

这是我对 getPerms 的新实现功能,灵感来自托马斯的回答。

不幸的是,它并不比现有的快。建议?
let getPerms n lst =
let rec getPermsImpl acc n lst = seq {
match n, lst with
| k, x :: xs ->
if k > 0 then
for r in getRotations lst do
yield! getPermsImpl (List.head r :: acc) (k - 1) (List.tail r)
if k >= 0 then yield! getPermsImpl acc k []
| 0, [] -> yield acc
| _, [] -> ()
}
getPermsImpl List.empty n lst

最佳答案

我注意到您更新的 getPerms 函数包含重复项。这是我对无欺骗版本的破解。希望评论不言自明。最难的部分是写一个高效的 distrib函数,因为必须在某处使用连接运算符。幸运的是它只用于小的子列表,所以性能仍然合理。我下面的 getAllPerms 代码在大约四分之一秒内生成 [1..9] 的所有排列,在大约 2.5 秒内生成所有 10 元素排列。

编辑:有趣的是,我没有看 Tomas 的代码,但他的组合功能和我的选择功能几乎相同。

// 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

编辑:响应评论的更多代码
// 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

关于f# - F# 中的组合和排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4495597/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com