我一直在学习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].
据我了解,列表推导无法提前看到,所以我无法使用之前的抓取功能。这再次让我觉得必须有更好的方法来解决这个问题。
答案 0 :(得分:3)
我在下面展示了几种方法。所有这些都可以防止请求的子列表长度大于列表长度的情况。所有都使用标准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
函数具有相同的名称。我建议避免将命名命名与常用的标准函数相同。