我有两个清单:
let a = ["a";"b"];
let b = ["c";"d"];
我想要一个输出列表c,例如:
c = ["a";"c";"a";"d";"b";"c";"b";"d"];
如何在ocaml中执行此操作,因为列表是不可变的?我是新手。
答案 0 :(得分:14)
您将返回一个新列表。如果你真的对列表中的笛卡儿产品感兴趣,那么这就足够了:
let cartesian l l' =
List.concat (List.map (fun e -> List.map (fun e' -> (e,e')) l') l)
# cartesian ["a";"b"] ["c";"d"];;
- : (string * string) list = [("a", "c"); ("a", "d"); ("b", "c"); ("b", "d")]
如果您需要这种奇怪的扁平结构,则可以使用其他列表连接。
let flat_cartesian l l' =
List.concat (List.concat (
List.map (fun e -> List.map (fun e' -> [e;e']) l') l))
答案 1 :(得分:3)
如果您不想使用连接,因为这不是尾递归操作,您可以使用以下(这应该更有效):
let product l1 l2 =
List.rev (
List.fold_left
(fun x a ->
List.fold_left
(fun y b ->
b::a::y
)
x
l2
)
[]
l1
)
;;
对于笛卡尔积,只需更改
即可b::a::y
到
(a,b)::y
答案 2 :(得分:2)
我会将问题分解为两个子问题:
首先考虑一个带有值和列表的函数appendeach,并返回在列表中的每个项目前面添加该值的结果
let rec appendeach x lst = match lst with [] -> []
| hd::tl -> x::hd::(appendeach x tl);;
然后考虑一个带有两个列表的函数产品,并为第一个列表和第二个列表中的每个项调用appendeach
let rec product lst1 lst2 = match lst1 with [] -> [] |
hd::tl -> (appendeach hd lst2)@(product tl lst2);;
答案 3 :(得分:0)
一个非常必要的(类 java 或 C 类)解决方案,所以我不确定它会有所帮助;在像 OCaml 这样的函数式语言中,通常期望递归而不是循环。但它有效:
let cartesianProduct list1 list2 =
let product = ref [] in
for i = 0 to List.length list1 -1 do
for j = 0 to List.length list2 -1 do
product:= !product@[List.nth list1 i]@[List.nth list2 j]
done;
done;
!product;;