作为一项学术练习,我尝试使用OCaml语言生成列表的所有可能排列,并且不能使用for循环。我可以使用变量,递归,模式匹配和if-else控件。
这是我到目前为止的想法:因为我可以使用递归,如果我想生成列表[1; 2; 3]的所有6个排列,那么我可以与h进行模式匹配:: t其中h是1而t是[2; 3],并假设我有[2; 3]的所有排列。然后我想循环遍历[2; 3]在每个可能的坐标中插入1的所有这些排列:0,1和2.所以例如用[2; 3]我想生成[1; 2; 3]和[2; 1; 3]和[2; 3; 1],然后对于[3; 2]我想生成[1; 3; 2]和[3; 1; 2]和[3; 2; 1]。
但是有一些明显的问题。一个是我需要用这些工具告诉计算机如何插入 - 但我已经知道了。我还需要"循环"在所有较小的排列上,然后遍历所有坐标,这是我不允许做的事情。这就是我被困的地方。
这就是我所做的:
(* This successfully does insertion of v into l at pos.*)
let rec insert_at_i (v: int) (l: int list) (pos: int) : int list =
begin match (l, pos) with
| (_, 0) -> v::l
| ([], _) -> failwith "invalid insert_at_i"
| (h::t, _) -> h::(insert_at_i v t (pos - 1))
end
(* This finds the length of a list.*)
let rec len (l: int list) : int =
begin match l with
| [] -> 0
| h::t -> (1 + (len t))
end
(* Here I'm trying to take a value like 1 and a list like [2;3] and
generate the list of all lists where 1 is inserted somewhere. Since I
can't loop, I tried thinking of a way to pattern-match, but it's not
working out. I tried to make extra parameters for basically keeping
track of the recursion's results as I go, but I'm running into the
problem that in a functional language like this, variables can't be re-
written with their side-effects stored, so to speak. *)
let rec insert_ith_at_i (v: int) (l: int list) (pos: int) (sofar: int list list): int list list =
if (l = []) then [[v]]
else if (pos > (len l)) then sofar
else (insert_ith_at_i v l (pos + 1) )
任何指导或点击都表示赞赏。
答案 0 :(得分:1)
这是一个解决方案 - 我首先定义了一些辅助函数:
let ( ^^ ) e ll = List.map (fun x -> e::x) ll
此函数为列表中包含的每个列表添加一个元素:
1 ^^ [[2; 3]; [3; 2]] gives : [[1; 2; 3]; [1; 3; 2]]
然后是permut
函数:
let rec permut l r = /* l : left, r right */
match r with
| [] -> [[]]
| [x] -> x ^^ (permut [] l)
| x::t -> let s = permut (x::l) t in
(x ^^ (permut [] (l@t))) @ s;;
permut [] [1;2;3];
算法运行如下: