如何在ReasonML中的列表末尾附加元素(相当于JavaScript中的Array.concat
)?
答案 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
答案 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, ...)
,因为它指向旧Nil
和Cons(2, ...)
,因为它指向旧Cons(3, ...)
,依此类推整个列表。每次添加元素时都必须这样做。这很快就会增加。
那你该怎么做呢?
如果你要添加到最后并且只是迭代它或者总是把元素放在最后,就像你经常在JavaScript中那样,你很可能只是颠倒你的逻辑。
,而不是添加和结束。如果您确实需要FIFO数据结构,其中元素在一端插入并在另一端取消,请考虑使用Queue。一般来说,请查看this comparison of the performance characteristics of the standard containers。
或者,如果这一切都有点多,并且你真的喜欢这样做,就像你习惯使用JavaScript一样,只需使用array
而不是list
。您可以在Js.Array
module