[英]How to split a list of strings into given number of lists in erlang
給定一個列表和一個整數,我想將該列表拆分為指定數量的列表(在列表內部)。
例如:
輸入:
[1,2,3,4,5,6,7,8,9], 3
輸出:
[[1,2,3],[4,5,6],[7,8,9]]
什么是清潔有效的方法?
您可以為此使用lists:split/2
:
divide(L, N) ->
divide(L, N, []).
divide([], _, Acc) ->
lists:reverse(Acc);
divide(L, N, Acc) when length(L) < N ->
lists:reverse([L|Acc]);
divide(L, N, Acc) ->
{H,T} = lists:split(N, L),
divide(T, N, [H|Acc]).
第一個函數divide/2
用作入口點。 它僅使用空列表的初始累加器值調用輔助函數divide/3
,然后divide/3
完成所有工作。 當列表已被完全處理時, divide/3
的第一個子句匹配,因此它只是反轉累加器並返回該值。 第二個子句處理L
的長度小於請求的N
值的情況; 它通過在Acc
前面加上L
,然后返回該新累加器的相反值來創建一個新累加器。 第三個子句首先調用lists:split/2
,將傳入的列表拆分為H
(它是N
元素的列表),以及T
(列表的其余部分)。 然后,它遞歸調用自身,將T
作為新的列表值,原始N
值以及一個新的累加器,該累加器由H
作為第一個元素,而原始累加器Acc
作為尾部。
史蒂夫·維諾斯基 ( Steve Vinoski)編寫的解決方案為每個分區調用了length/1
作為保護,使其變為 O(N^2)
。 這簡直讓我感到困擾,因為它可以在O(N)
完成,而且我表現出色。 它可以通過多種方式完成,因此僅舉一個例子:
divide(L, N) when is_integer(N), N > 0 ->
divide(N, 0, L, []).
divide(_, _, [], Acc) ->
[lists:reverse(Acc)];
divide(N, N, L, Acc) ->
[lists:reverse(Acc) | divide(N, 0, L, [])];
divide(N, X, [H|T], Acc) ->
divide(N, X+1, T, [H|Acc]).
或作為Steve解決方案的修改
divide(L, N) ->
divide(L, N, []).
divide([], _, Acc) ->
lists:reverse(Acc);
divide(L, N, Acc) ->
try lists:split(N, L) of
{H,T} -> divide(T, N, [H|Acc])
catch
error:badarg ->
lists:reverse([L|Acc])
end.
甚至更簡單:
divide([], _) -> [];
divide(L, N) ->
try lists:split(N, L) of
{H,T} -> [H|divide(T, N)]
catch
error:badarg -> [L]
end.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.