所以我是 OCaml 的新手,并且在列表方面遇到了一些问题。 我所拥有的是如下字符列表:
let letters = [a;b;c;d]
我想知道如何迭代列表并应用一个函数,该函数将列表中两个字符的每个可能组合(do_someting char1 char2)作为参数,例如: a 和 b (do_something a b)、 a 和 c 。 ... d 和 b,d 和 c;永远不要重复相同的元素(a 和 a 或 c 和 c 不应该发生)。
OCaml 是一种函数式语言,因此我们希望尝试将过程分解为尽可能多的函数块。
第一步是“列出事物列表并产生所有组合”。我们不在乎之后会发生什么;我们只想知道所有这些组合。如果您希望每个组合仅出现一次(即,在您的示例中,
(a, b)
将出现,但(b, a)
不会出现),那么一个简单的递归定义就足够了。
let rec ordered_pairs xs =
match xs with
| [] -> []
| (x :: xs) -> List.append (List.map (fun y -> (x, y)) xs) (ordered_pairs xs)
如果您想要反转的重复项(
(a, b)
和 (b, a)
),那么我们可以将它们添加到最后。
let swap (x, y) = (y, x)
let all_ordered_pairs xs =
let p = ordered_pairs xs in
List.append p (List.map swap p)
现在我们有了所有元组的列表。接下来会发生什么取决于你想要什么样的结果。您很可能正在查看内置
List
模块 中的某些内容。如果您想将该函数应用于每对以产生副作用,那么 List.iter
就可以了。如果你想将结果累积到一个新列表中,List.map
就可以做到。如果您想应用一些操作来组合结果(例如,每个函数返回一个数字,并且您想要数字的总和),那么 List.map
后跟 List.fold_left
(或复合 List.fold_left_map
)就可以了。
当然,如果您刚刚开始,自己编写这些
List
函数可能会很有启发。它们中的每一个都是简单的一两行递归定义,对于您自己编写非常有启发性。
作为 Silvio 答案的附录,对于大型列表,我们不需要在内存中实际生成整个列表,然后对其进行迭代。相反,我们可以创建一个有序对的序列。
为了做到这一点,我们需要跟踪三件事:
let rec ordered_pairs_seq lst () =
let rec aux pre cur_lst lst () =
match cur_lst, lst with
| [], _ -> ordered_pairs_seq lst ()
| x::xs, _ -> Seq.Cons ((pre, x), aux pre xs lst)
in
match lst with
| [] -> Seq.Nil
| x::xs -> aux x xs xs ()
然后使用这个:
# let print_tuple (a, b) =
Printf.printf "(%d, %d)\n" a b
in
pairs_seq [1; 2; 3; 4; 5]
|> Seq.iter print_tuple;;
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 3)
(2, 4)
(2, 5)
(3, 4)
(3, 5)
(4, 5)
- : unit = ()
当然,如果您需要整个列表:
# pairs_seq [1; 2; 3; 4; 5]
|> List.of_seq;;
- : (int * int) list =
[(1, 2); (1, 3); (1, 4); (1, 5); (2, 3); (2, 4); (2, 5);
(3, 4); (3, 5); (4, 5)]