在列表末尾追加一个元素

Append an element at the end of a list

如何在 ReasonML 中的列表末尾追加元素(相当于 JavaScript 中的 Array.concat)?

您可以使用 List.append@ 运算符,即 shorthand 用于 List.append

let lstA = [ 1 ];
let lstB = lstA @ [ 2 ];
let lstC = List.append(lstB, [ 3 ]);

这是列表方法的文档:https://reasonml.github.io/api/List.html

在此处查看游乐场 link:https://reasonml.github.io/en/try.html?reason=DYUwLgBMDOYIIQLwQNoQIwQLoG4BQokMYAQklLAgAKoQBM2+hFYAwuQDICWsAdAIYAHQSAB2AEwAUxEgBpaAZmwBKfEA

虽然 Neil 的回答在技术上是正确的,但它掩盖了您在寻求 append 之前可能需要考虑的一些细节;具体来说,虽然将一个元素添加到列表的开头非常便宜,但将一个元素添加到列表的末尾非常昂贵。

要了解原因,让我们看一下列表是如何定义和构造的。列表的(概念)定义是:

// Reason
type list('a) = Cons('a, list('a)) | Nil;
(* OCaml *)
type 'a list = Cons of 'a* 'a list | Nil

其中 Nil 表示列表的末尾(并且它本身是一个空列表)并且 Cons 表示列表中的一个节点,包含一个 'a 类型的元素和一个指向列表其余部分的指针(list('a),OCaml:'a list)。

如果我们去掉所有的语法糖和每个辅助函数,你将不得不构建一个这样的列表:

// Reason
let myList = Cons(1, Cons(2, Cons(3, Nil)));
(* OCaml *)
let myList = Cons (1, Cons (2, Cons (3, Nil)))

然后,为了向该列表的头部添加一个元素,我们构造一个包含新元素和指向旧列表的指针的节点:

// Reason
let myBiggerList = Cons(0, myList);
(* OCaml *)
let myBiggerList = Cons (0, myList)

这与 [0, ...myList] (OCaml: 0 :: myList) 完全相同。如果 myList 可以改变,我们当然不能这样做,但我们知道它不会,因为列表是不可变的。这使得它非常便宜,出于同样的原因,它也同样便宜,这就是为什么您通常会看到使用递归实现的列表处理函数,如下所示:

// Reason
let rec map = f =>
  fun | []         => []
      | [x, ...xs] => [f(x), ...map(f, xs)];
(* OCaml *)
let rec map f = function
  | [] -> []
  | x::xs -> (f x) :: (map f xs)

好吧,那么为什么在列表尾部添加一个元素如此昂贵?如果你回头看myList,添加一个元素到结束意味着用 Cons(4, Nil) 替换最后的 Nil。但随后我们需要替换 Cons(3, ...),因为它指向旧的 Nil,而 Cons(2, ...) 因为它指向旧的 Cons(3, ...),依此类推整个列表。每次添加元素时都必须这样做。这很快就加起来了。

那么你应该怎么做呢?

如果您要添加到末尾并只是遍历它或总是从末尾删除元素,就像您在 JavaScript 中经常做的那样,您很可能只是颠倒了您的逻辑。不要在结尾添加和删除,而是在开头添加和删除。

如果您确实需要一个 FIFO 数据结构,其中元素在一端插入并在另一端取出,请考虑使用 Queue instead. In general, have a look at this comparison of the performance characteristics of the standard containers

或者,如果这有点多,而您真的只是想像从 JavaScript 开始那样做,只需使用 array 而不是 [=35] =].您会在 Js.Array module

中找到您熟悉的所有功能