【问题标题】:Sublists of N length function in Erlang styleErlang 风格的 N 长度函数的子列表
【发布时间】:2015-03-23 18:37:08
【问题描述】:

我一直在学习 Erlang,并尝试完成一些练习功能。我特别努力地制作一个函数,并认为这可能是因为我对“Erlang”的思考不够。

有问题的函数接受一个列表和一个子列表大小,然后生成一个元组列表,其中包含子列表之前的元素数量、子列表本身以及子列表之后的元素数量。例如

sublists(1,[a,b,c])=:=[{0,[a],2}, {1,[b],1}, {2,[c],0}].
sublists(2,[a,b,c])=:=[{0,[a,b],1}, {1,[b,c],0}].

我的工作解决方案是

sublists(SubListSize, [H | T]) ->
    Length = length(1, T),
    sublists(SubListSize, Length, Length-SubListSize, [H|T], []).
sublists(_, _, -1, _, Acc) -> lists:reverse(Acc);
sublists(SubSize, Length, Count, [H|T], Acc) ->
    Sub = {Length-SubSize-Count, grab(SubSize, [H|T],[]),Count},
    sublists(SubSize, Length, Count-1, T, [Sub|Acc]).

length(N, []) -> N;
length(N, [_|T]) -> length(N+1, T).

grab(0, _, Acc) -> lists:reverse(Acc);
grab(N, [H|T], Acc) -> grab(N-1, T, [H|Acc]).

但感觉不对劲,我想知道是否有更好的方法?

有一个扩展要求使用列表推导重新实现子列表功能。我的失败尝试是

sublist_lc(SubSize, L) ->
    Length = length(0, L),
    Indexed = lists:zip(L, lists:seq(0, Length-1)),
    [{I, X, Length-1-SubSize} || {X,I} <- Indexed, I =< Length-SubSize].

据我了解,列表推导式无法预见,因此我无法使用之前的抓取功能。这再次让我觉得必须有更好的方法来解决这个问题。

【问题讨论】:

    标签: functional-programming erlang


    【解决方案1】:

    我在下面展示了一些方法。所有这些都可以防止请求的子列表长度大于列表长度的情况。所有使用标准lists module中的函数。

    第一个使用lists:split/2 来捕获每个子列表和剩余尾列表的长度,并使用计数器C 来跟踪子列表之前有多少元素。剩余尾列表的长度,名为Rest,给出了每个子列表后面的元素数。

    sublists(N,L) when N =< length(L)  ->
        sublists(N,L,[],0).
    sublists(N,L,Acc,C) when N == length(L) ->
        lists:reverse([{C,L,0}|Acc]);
    sublists(N,[_|T]=L,Acc,C) ->
        {SL,Rest} = lists:split(N,L),
        sublists(N,T,[{C,SL,length(Rest)}|Acc],C+1).
    

    下一个使用两个计数器列表,一个指示子列表前面有多少元素,另一个指示它后面有多少元素。第一个很容易通过简单地从 0 计数到输入列表的长度减去每个子列表的长度来计算,第二个计数器列表正好与第一个相反。这些计数器列表也用于控制递归;当每个只包含一个元素时,我们停止,表明我们已经到达最终的子列表并且可以结束递归。此方法使用lists:sublist/2 调用来获取除最终子列表之外的所有子列表。

    sublists(N,L) when N =< length(L) ->
        Up = lists:seq(0,length(L)-N),
        Down = lists:reverse(Up),
        sublists(N,L,[],{Up,Down}).
    sublists(_,L,Acc,{[U],[D]}) ->
        lists:reverse([{U,L,D}|Acc]);
    sublists(N,[_|T]=L,Acc,{[U|UT],[D|DT]}) ->
        sublists(N,T,[{U,lists:sublist(L,N),D}|Acc],{UT,DT}).
    

    最后,这是一个基于列表理解的解决方案。它与前面的解决方案类似,因为它使用两个计数器列表来控制迭代。它还利用lists:nthtail/2 和lists:sublist/2 来获取每个子列表,诚然效率不高;毫无疑问,它可以改进。

    sublists(N,L) when N =< length(L) ->
        Up = lists:seq(0,length(L)-N),
        Down = lists:reverse(Up),
        [{U,lists:sublist(lists:nthtail(U,L),N),D} || {U,D} <- lists:zip(Up,Down)].
    

    哦,请注意:您的代码实现了一个名为 length/2 的函数,这有点令人困惑,因为它与标准 length/1 函数同名。我建议避免将您的函数命名为与常用的标准函数相同的名称。

    【讨论】:

      猜你喜欢
      • 2017-06-23
      • 1970-01-01
      • 2021-03-13
      • 1970-01-01
      • 1970-01-01
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      • 2016-12-04
      相关资源
      最近更新 更多