你如何在 OCaml/ReasonML 中获取列表的一部分?

How do you take a slice of a list in OCaml/ReasonML?

例如,在 Ruby 中,您可以执行以下操作:

list = ["foo", "bar", "baz", "qux", "quux", "corge"]
result = list[2..4]

result 将包含 ["baz", "qux", "quux"]

在 OCaml/ReasonML 中你会怎么做?

OCaml 切片没有特殊的语言符号。你可以编写你的函数,比如使用模式匹配,或者将 head 与 take 函数结合起来(这些在标准库中可用)。对于 Reason 组合 List.hd 和 List.tk https://reasonml.github.io/api/List.html , also Array module has a sublist Array.sub. The OCaml was discussed here how to get a sub list from a list in ocaml

如果您有权访问 bucklescript 的 Belt 库,您可以执行以下操作:

open Belt;

let myList = ["first", "second", "third", "fourth", "fifth", "sixth"];

/* To get 2..4 */
myList
  ->List.drop(2)
  ->Option.getWithDefault([])
  ->List.take(3)
  ->Option.getWithDefault([])
  ->Js.log;

/* Gives you the list ["third", "fourth", "fifth"] */

切片列表没有内置函数,但可以轻松完成。 由于我们有起点和终点,我们可以将问题分解为两部分。第一部分是 drop 几个元素,直到我们到达起点,第二部分是 take 从起点到终点的几个元素。

let rec drop = (n, list) =>
  switch (list) {
  | [] => []
  | [_, ...xs] as z => n == 0 ? z : drop(n - 1, xs)
  };

let rec take = (n, list) =>
  switch (list) {
  | [] => []
  | [x, ...xs] => n == 0 ? [] : [x, ...take(n - 1, xs)]
  };

现在我们有了这两个函数,我们可以将它们组合起来从开始点开始删除初始元素 drop(i, list) 然后传递这个新列表以从开始点到结束点获取元素

take(k - i + 1, drop(i, list));

let slice = (list, i, k) => {

  let rec drop = (n, list) =>
    switch (list) {
    | [] => []
    | [_, ...xs] as z => n == 0 ? z : drop(n - 1, xs)
    };

  let rec take = (n, list) =>
    switch (list) {
    | [] => []
    | [x, ...xs] => n == 0 ? [] : [x, ...take(n - 1, xs)]
    };

  take(k - i + 1, drop(i, list));
};

更好的方法是先提供起点再提供范围而不是终点,因为这里我们不限制终点应该大于起点

let slice = (list, start, range) => {

  let rec drop = (n, list) =>
    switch (list) {
    | [] => []
    | [_, ...xs] as z => n == 0 ? z : drop(n - 1, xs)
    };

  let rec take = (n, list) =>
    switch (list) {
    | [] => []
    | [x, ...xs] => n == 0 ? [] : [x, ...take(n - 1, xs)]
    };

  take(range, drop(start, list));
};

如果您有权访问 BuckleScript,您可以使用:

let list = ["foo", "bar", "baz", "qux", "quux", "corge"];

let sliced = Js.Array.slice(~start=2, ~end_=4, list);

BuckleScript docs

中查看更多内容

使用

List.filteri (fun i _ -> i >= start && i <= end)