在Erlang中将平面列表转换为一组二元组的最佳方法?

5 algorithm erlang list

有没有一种快速的方法将平面列表转换为两元组列表,使得像[1,2,3,4,5,6]这样的平面列表变为[{1,2},{3,4}, {5,6}]?

这有效,但感觉非常错误:

tuples_from_flat_list(Target) ->
    TargetWithIndex = lists:zip(lists:seq(1, length(Target)), Target),
    {K, V} = lists:partition(fun({I, _}) -> I rem 2 == 1 end, TargetWithIndex),
    lists:zipwith(fun({_, X}, {_, Y}) -> {X, Y} end, K, V).
Run Code Online (Sandbox Code Playgroud)

Chr*_*ian 10

最简洁,最简洁的方法:

pair_up([A, B | Tail]) ->
    [{A,B} | pair_up(Tail)];
pair_up([]) ->
    [].
Run Code Online (Sandbox Code Playgroud)

或者带有累加器的较长版本,但仍然是非常惯用的Erlang:

pair_up(List) ->
    pair_up(List, []).

pair_up([A, B | Tail], Acc) ->
    pair_up(Tail, [{A,B} | Acc]);
pair_up([], Acc) ->
    lists:reverse(Acc).
Run Code Online (Sandbox Code Playgroud)

请参阅erlang效率指南 "神话:尾递归函数比递归函数快得多"中的本节.

正如您将注意到的,当使用不均匀长度列表调用时,这两种方法都将导致"badarg"退出.从快速失败的角度来看,这可能是可取的.

另外阅读"神话:'++'总是坏的",看看为什么我们反向建立累加器只是在完成后反转它,而不是附加到列表的末尾.


zak*_*rya 2

这个版本比之前提出的列表串联的“直接”方法更有效:

combine(L) when length(L) rem 2 == 0 -> combine([], L).
combine(Acc, []) -> lists:reverse(Acc);
combine(Acc, [H1,H2|T])  -> combine([{H1, H2}|Acc], T).
Run Code Online (Sandbox Code Playgroud)

进行基准测试:

组合.erl

-module(combine).
-export([reverse/1, straight/1, test/2]).

test(F, L) -> {Micros, _} = timer:tc(?MODULE, F, [L]), Micros.

reverse(L) when length(L) rem 2 == 0 -> reverse([], L).                                  
straight(L) when length(L) rem 2 == 0 -> straight([], L).

reverse(Acc, []) -> lists:reverse(Acc);
reverse(Acc, [H1, H2 | T]) -> reverse([{H1, H2} | Acc], T).

straight(Acc, []) -> Acc;
straight(Acc, [H1, H2 | T]) -> straight(Acc ++ [{H1, H2}], T).
Run Code Online (Sandbox Code Playgroud)

输出:

130> combine:test(reverse, lists:seq(1,1000)).
34
131> combine:test(straight, lists:seq(1,1000)).
1772
Run Code Online (Sandbox Code Playgroud)