在列表末尾附加元素

时间:2018-03-01 13:43:50

标签: list ocaml reason

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

2 个答案:

答案 0 :(得分:8)

您可以使用List.append@运算符,它是List.append的简写。

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

以下是List方法的文档:https://reasonml.github.io/api/List.html

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

答案 1 :(得分:6)

虽然Neil的回答在技术上是正确的,但它会掩盖您在达到append之前可能要考虑的一些细节;特别是在向列表开头添加元素非常便宜时,在结尾添加元素非常昂贵。

要理解原因,让我们看看如何定义和构建列表。列表的(概念性)定义是:

type list('a) = Cons('a, list('a)) | Nil;

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

如果我们拿走了所有语法糖和每个辅助函数,你就必须构造一个这样的列表:

let myList = Cons(1, Cons(2, Cons(3, Nil)));

要在此列表的头部添加元素,我们构造一个包含新元素的节点和一个指向旧列表的指针:

let myBiggerList = Cons(0, myList);

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

let rec map = f =>
  fun | []         => []
      | [x, ...xs] => [f(x), ...map(f, xs)];

好的,那么为什么在列表的尾部添加元素会如此昂贵呢?如果你回顾myList,在末尾添加一个元素就意味着要替换它最后Nil,例如Cons(4, Nil)。但是,我们需要替换Cons(3, ...),因为它指向旧NilCons(2, ...),因为它指向旧Cons(3, ...),依此类推整个列表。每次添加元素时都必须这样做。这很快就会增加。

那你该怎么做呢?

如果你要添加到最后并且只是迭代它或者总是把元素放在最后,就像你经常在JavaScript中那样,你很可能只是颠倒你的逻辑。

,而不是添加和结束。

如果您确实需要FIFO数据结构,其中元素在一端插入并在另一端取消,请考虑使用Queue。一般来说,请查看this comparison of the performance characteristics of the standard containers

或者,如果这一切都有点多,并且你真的喜欢这样做,就像你习惯使用JavaScript一样,只需使用array而不是list。您可以在Js.Array module

中找到您熟悉的所有功能