如何在可迭代列表中应用函数

问题描述 投票:0回答:2

所以我是 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 不应该发生)。

list function loops functional-programming ocaml
2个回答
4
投票

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
函数可能会很有启发。它们中的每一个都是简单的一两行递归定义,对于您自己编写非常有启发性。


0
投票

作为 Silvio 答案的附录,对于大型列表,我们不需要在内存中实际生成整个列表,然后对其进行迭代。相反,我们可以创建一个有序对的序列

为了做到这一点,我们需要跟踪三件事:

  • 当前前缀。
  • 该前缀之后的列表的其余部分。
  • 前缀again之后的列表的其余部分,以便我们可以更新第一个参数,并且当我们迭代到该列表的末尾时仍然拥有它。
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)]
© www.soinside.com 2019 - 2024. All rights reserved.