Erlang中根据元素位置将给定列表拆分为子列表的最正确(也是最快)方法是什么?例如。我想得到列表中每个第N个元素的子列表:[1,2,3,14,5,16,7,8]到[1,14,7],[2,5,8],[3, 16]? N可以有任何合理的价值。
答案 0 :(得分:1)
没有功能可以过滤列表中的位置,因此您必须使用split:
1> Sp = fun Sp(L,N,R) when length(L) =< N -> lists:reverse([L|R]);
1> Sp(L,N,R) -> {L1,L2} = lists:split(N,L), Sp(L2,N,[L1|R]) end.
#Fun<erl_eval.42.90072148>
2> Split= fun (L,N) when is_list(L), is_integer(N), N > 0 -> Sp(L,N,[]) end.
#Fun<erl_eval.12.90072148>
3> Split([1,2,3,4,5,6,7,8],3).
[[1,2,3],[4,5,6],[7,8]]
4>
[edit] 哎呀,它没有回答这个问题。如果您不介意子列表的顺序,可能还有其他解决方案
1> L = [1,2,3,4,5,6,7,8].
[1,2,3,4,5,6,7,8]
2> N = 3.
3
3> [lists:reverse(Y) || Y <- lists:foldl(fun(X,[H|T]) -> T++[[X|H]] end , lists:duplicate(N,[]),L)].
[[3,6],[1,4,7],[2,5,8]]
4>
下一个版本恢复订单:
1> F = fun(List,Chunk) -> {Si,L1} = lists:foldl(fun(X,{S,[H|T]}) -> {S+1,T++[[X|H]]} end , {0,lists:duplicate(Chunk,[])},List),
1> {L2,L3} = lists:split(Chunk - Si rem Chunk,L1),
1> [lists:reverse(Y) || Y <- L3 ++ L2] end.
#Fun<erl_eval.12.90072148>
2> F(lists:seq(1,130),11).
[[1,12,23,34,45,56,67,78,89,100,111,122],
[2,13,24,35,46,57,68,79,90,101,112,123],
[3,14,25,36,47,58,69,80,91,102,113,124],
[4,15,26,37,48,59,70,81,92,103,114,125],
[5,16,27,38,49,60,71,82,93,104,115,126],
[6,17,28,39,50,61,72,83,94,105,116,127],
[7,18,29,40,51,62,73,84,95,106,117,128],
[8,19,30,41,52,63,74,85,96,107,118,129],
[9,20,31,42,53,64,75,86,97,108,119,130],
[10,21,32,43,54,65,76,87,98,109,120],
[11,22,33,44,55,66,77,88,99,110,121]]
3>
答案 1 :(得分:1)
你真的需要最快的方式吗?每次我以最简单(最天真)的方式开始实施。只有当我意识到它是性能瓶颈时,我才会开始优化它。
所以,最天真的方式:
split(List, ByElem) ->
do_split(List, lists:duplicate(ByElem, []), []).
do_split([], RestGroups, Acc) ->
Groups = lists:reverse(Acc) ++ RestGroups,
[ lists:reverse(G) || G <- Groups ];
do_split([Elem | Rest], [Group | RestGroups], Acc) ->
do_split(Rest, RestGroups, [[Elem | Group] | Acc]);
do_split(List, [], Acc) ->
do_split(List, lists:reverse(Acc), []).
实际上,我认为与此代码的性能无关,我也没有看到任何方法来显着改进它。