++运算符比|更昂贵 Erlang中的运算符?

tMJ*_*tMJ 4 erlang

我正在阅读Learn You Some Erlang,我在Recursion章节中找到了这个例子.

tail_sublist(_, 0, SubList) -> SubList;
tail_sublist([], _, SubList) -> SubList;
tail_sublist([H|T], N, SubList) when N > 0 -> 
tail_sublist(T, N-1, [H|SubList]).
Run Code Online (Sandbox Code Playgroud)

正如作者继续解释我们的代码中存在致命缺陷.因此产生的子列表将是反向的,我们将不得不重新反转它们以获得正确的输出.相反,我所做的是使用++运算符来避免以后反转列表.

sublist_tail([],_,Acc) -> Acc;
sublist_tail(_,0,Acc) -> Acc;
sublist_tail([H|T],N,Acc) -> sublist_tail(T,N-1,Acc++[H]).
Run Code Online (Sandbox Code Playgroud)

我的问题是,++不是运营商更昂贵的|运营商?如果是这样,与作者的解决方案(包括反转列表以获得正确的输出)相比,我的解决方案(使用++运算符)是否仍然会很慢?

Ste*_*ski 6

您可能希望在Erlang效率指南中阅读此问题,因为它表示通过构建列表|然后反转结果比使用附加++运算符更有效.如果您想了解性能差异,请使用timer:tc:

1> timer:tc(fun() -> lists:reverse(lists:foldl(fun(V, Acc) -> [V|Acc] end, [], lists:seq(1,1000))) end).
{1627,
 [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
  23,24,25,26,27|...]}
2> timer:tc(fun() -> lists:foldl(fun(V, Acc) -> Acc++[V] end, [], lists:seq(1,1000)) end).
{6216,
 [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
  23,24,25,26,27|...]}
Run Code Online (Sandbox Code Playgroud)

这两种方法都创建了1000个整数的列表,但这些基于Erlang/OTP 17.5的测量显示,前置/反转版本比附加版本(当然是YMMV)大约快4倍.

  • 使用相同系统测量100000个整数表示前置/反转版本的时间比1000整数版本整齐地增加了100倍,正如您所期望的那样,但是附加版本的时间增加了大约4500倍.必须不断遍历列表以附加到它. (2认同)