2009-07-27 1 views
5

[1,2,3,4,5,6]のようなフラットなリストが[{1,2}、{3,4のようになるようにフラットリストを2つのタプルのリストに素早く変換する方法はありますか}、{5,6}]?フラインリストをErlangの2タプルに変換する最も良い方法は?

これは動作しますが、それは単純に間違っを感じている:

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). 

答えて

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). 

ベンチマーク:

combine.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). 

出力:

130> combine:test(reverse, lists:seq(1,1000)). 
34 
131> combine:test(straight, lists:seq(1,1000)). 
1772 
+0

はい、逆転と接頭辞は常に効率的です。しかし、私は "ストレート"アプローチがレッスン1としてうまくいき、レッスン2と同じように逆順/接頭辞がすぐに続くと思います。 –

+0

もっと重要なエラーメッセージを表示しないときにリストの長さをカウントする理由あなたの逆/ 2はあなたの逆/ 1と同じエラーメッセージを発生させます。それは無駄な仕事であり、それを少し遅くする。 –

+1

@Hynek:早く失敗するので、より良いと思います。また、コードを読むつもりの人に明快さを加える。 – zakovyrya

3
tuples_from_flat_list(List) -> tuples_from_flat_list(List, []). 

tuples_from_flat_list([], Result) -> lists:reverse(Result). 
tuples_from_flat_list([X, Y|T], Acc) -> tuples_from_flat_list(T, [{X, Y}|Acc]). 

それが最善かつ最速の方法です。

+0

リストやガードのない場合でも、リスト処理の最後ですべての作業がほぼ終了しても失敗する。 **例外エラー:関数節に一致するテストがありません:tuples_from_flat_list([5]、[{3,4}、{1,2}]) – zakovyrya

+0

はい、意図的です。 –

10

最短と最も簡潔なアプローチ:

pair_up([A, B | Tail]) -> 
    [{A,B} | pair_up(Tail)]; 
pair_up([]) -> 
    []. 

又は蓄電池を運ぶ長いバージョンが、それでも非常に慣用的なアーラン:

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

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

はアーラン効率ガイド "Myth: Tail-recursive functions are MUCH faster than recursive functions"に、このセクションを参照してください。

あなたが気づくように、両方のアプローチでは、長さのリストが不揃いで呼び出されたときに「badarg」が終了します。これはおそらくフェイル・ファーストの観点から望ましいでしょう。

"Myth: '++' is always bad"も読んで、アキュムレータを逆順に構築して、リストの末尾に追加するのではなく、逆転させる理由を確認してください。

関連する問題