我怎么能写Erlang的列表串连,而无需使用列表模块?(How can I write Erlang

2019-07-30 05:15发布

这本书我读关于二郎在它的背面有练习,一个是重新创建列表:附加功能。

我能做到这一点简单地使用++运算符,而不是这真的是慢? 而且我觉得练习的要点是用我写列表操作做到这一点。

到目前为止,我能想到的唯一的办法是做这样的事情:

concat([], _, Results)->
  Results;
concat(_, [], Results)->
  Results;
concat([Ah|At],B,Results) ->
  concat(At,B,[Ah|Results]).

但我知道这是不正确?

如何去这样做有什么建议?

编辑:为了澄清的问题,这里是一个例子的输入和输出:

输入:[[1,2,3],[],[4,5],[6]]输出:[1,2,3,4,5,6]

工作一段时间后,我想出了这个代码,以及:

append([A|[B|[T|[]]]]) ->
  append([A++B|T]);
append([H|T]) ->
  H++T.

然而,这仅适用于当列表的大小为3,我怎么能修改此所以它适用于任意大小的列表中任何给定的量?

Answer 1:

你只需要两个参数的concat函数,因为你会被追加到参数之一,这就是你最终会回来。 喜欢的东西(未经测试):

concat(L,[]) ->
   L;
concat(L,[H|T]) ->
   concat(L ++ [H],T).

该++是追加操作符,你将不得不这样做是有效的。

(上面的想法是返回左参数,如果我们已经没有更多的左,或移动的要素之一从右边到左边后再次调用)。 有大概在做反向的追加,然后终于扭转了答案更高的效率,但嘿...)

(刚看到你的编辑,当然,我的只适用于两件事情追加,但你可以通过在你的名单列表中的每个元素上面的函数递归...)



Answer 2:

++只慢误用时,使用小心地是一样快,任何你可以通过手工工艺。 你必须确保你通过在正确的方向列表工作,否则由此产生的追加为O(N ^ 2)。 当我们做X ++ Y,我们必须使X的副本,然后将其前面加上到不被复制年。

在这个函数中,蓄能器出现在++的左手侧,所以追加效率不高。

concatl(Lst) ->
    concatl(Lst, []).
concatl([], Acc) ->
    Acc;
concatl([H|T], Acc) ->
    concatl(T, Acc ++ H).

这个函数执行好多了,尽管它不是尾递归。

concat([]) -> [];
concat([H|T]) ->
    H ++ concat(T).

在这种情况下改写为尾递归只是略有改善:

concat2(Lst) ->
    concat2(lists:reverse(Lst), []).
concat2([], Acc) -> Acc;
concat2([H|T], Acc) ->
    concat2(T, H ++ Acc).

一个大的输入列表中的计时显示的改善是多么的庞大! (时间单位微秒)。

41> Time(fun() -> test:concatl([lists:seq(1,1000) || X <- lists:seq(1,1000)]) end).
14539061
40> Time(fun() -> test:concat([lists:seq(1,1000) || X <- lists:seq(1,1000)]) end).
245356
42> Time(fun() -> test:concat2([lists:seq(1,1000) || X <- lists:seq(1,1000)]) end).
211571


Answer 3:

一个绝妙的方法是使用lists:foldr

concat(A,B) ->
    lists:foldr(fun(X,XS) -> [X|XS] end, B, A).

concat(XS) ->
    lists:foldr(fun concat/2, [], XS). 

这也是一个很好的锻炼; Tibial写自己foldr相似功能...



Answer 4:

    -module(functional).
    -export([my_append/2,helper/2]).

    my_append(L1,L2) ->
      % concatenates lists L1 and L2
        functional:helper(lists:reverse(L1),L2).
    helper(L1,L2) ->
        if
            L1 == [] -> L2;
            L2 == [] -> L1;
            true     -> [H1|T1] = L1,
                        functional:helper(T1,[H1|L2])
        end.


文章来源: How can I write Erlang's list concatenate without using the lists module?