你如何在 OCaml/ReasonML 中截取一个列表?

Eri*_*rik 4 ocaml reason

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

list = ["foo", "bar", "baz", "qux", "quux", "corge"]
result = list[2..4]
Run Code Online (Sandbox Code Playgroud)

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

你会如何在 OCaml/ReasonML 中做到这一点?

shr*_*ynx 5

没有用于切片列表的内置功能,但可以轻松完成。由于我们有起点和终点,我们可以将问题分解为两部分。第一部分是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)]
  };
Run Code Online (Sandbox Code Playgroud)

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

take(k - i + 1, drop(i, list));
Run Code Online (Sandbox Code Playgroud)

总共

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));
};
Run Code Online (Sandbox Code Playgroud)

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

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));
};
Run Code Online (Sandbox Code Playgroud)