如何将字符串列表拆分为 erlang 中给定数量的列表
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
的第一个子句在列表已被完全处理时匹配,因此它只是反转累加器和 returns 该值。第二个子句处理 L
的长度小于请求的 N
值的情况;它通过在 Acc
前面添加 L
来创建一个新的累加器,然后返回该新累加器的反向。第三个子句首先调用 lists:split/2
将传入列表拆分为 H
,这是一个 N
元素的列表,以及 T
,列表的其余部分。然后它递归地调用自己,传递 T
作为新的列表值,原始的 N
值,以及一个由 H
作为第一个元素和原始累加器组成的新累加器,Acc
,作为尾巴。
written by 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.
给定一个列表和一个整数,我想将该列表拆分为指定数量的列表(在列表内)。
例如:
输入:
[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
的第一个子句在列表已被完全处理时匹配,因此它只是反转累加器和 returns 该值。第二个子句处理 L
的长度小于请求的 N
值的情况;它通过在 Acc
前面添加 L
来创建一个新的累加器,然后返回该新累加器的反向。第三个子句首先调用 lists:split/2
将传入列表拆分为 H
,这是一个 N
元素的列表,以及 T
,列表的其余部分。然后它递归地调用自己,传递 T
作为新的列表值,原始的 N
值,以及一个由 H
作为第一个元素和原始累加器组成的新累加器,Acc
,作为尾巴。
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.