2016-08-13 20 views
3

私は、アンガー値を含むerlangのリストを持っています。 一度だけ発生する値を削除したい(重複しない)。リスト要素を削除するのは一度だけです

Input = [1,3,2,1,2,2] 
Output = [1,2,1,2,2] 

私は初心者です。私は最初にlist:sort()を使ってそれらをソートする方法を試して、隣のメンバーが同じならメンバーを削除しています。 リストの反復処理に問題があります。あなたが私にそれをする方法を私に見せることができれば、大きな助けになるでしょう。

答えて

3

使用マップ。

-module(test). 
-export([remove_unique/1]). 

remove_unique(L) -> 
    Count = lists:foldl(fun count/2, #{}, L), 
    lists:filter(fun(X) -> maps:get(X, Count) =/= 1 end, L). 

count(X, M) -> 
    maps:put(X, maps:get(X, M, 0) + 1, M). 

とテスト:

1> c(test). 
{ok,test} 
2> test:remove_unique([1,2,3,3,3,5,5,6,7,7]). 
[3,3,3,5,5,7,7] 
3> test:remove_unique([1,2,3,3,3,5,5,6,7,8]). 
[3,3,3,5,5] 
4> test:remove_unique([1,3,2,1,2,2]).   
[1,2,1,2,2] 
ここ
+0

最高のソリューションをありがとう@Hynek –

+0

地図を使用して非常にいいと単純化されたソリューション。好奇心のためだけに、 'maps:'の時間の複雑さは何ですか? –

+1

@A.Sarid:理論上はO(1)であるが、実際はO(logN)である。私は、メモリまたはメモリそのものに線形のアドレス配列を含む実際に結合されていないK/VストレージのO(1)アクセス時間を持つ技術を聞いたり、見たことがありませんでした。実際に結合されていない解を考えるなら、この解はO(N * logN)です。 –

1

リストを反復する(結果として新しいリストを返す)1つの方法は、再帰とパターンマッチングを使用しています。

リストをソートした後、リストを繰り返し、次の要素と異なるだけでなく、その前に他の等しい要素がないことをチェックします。次の要素のみをチェックする場合はリスト[3,3,3,5,5]を考えてください。最後の3も一意であり、間違っています。

ここでは動作するプログラムですが、上記のケースもカバーするためにカウンタを使用しました。リストの反復処理には[H|T]の構文を参照してください。あなたはもっと多くのケースを見て、それについてもっと読むかもしれませんhere。値をカウントしてから一度だけ存在していなかった値をフィルタする

-module(test). 
-export([remove_unique/1]). 

remove_unique(Input) -> 
    Sorted = lists:sort(Input), 
    remove_unique(Sorted, [], 0). 
% Base case - checks if element is unique 
remove_unique([H|[]],Output,Count) -> 
    case Count of 
     0 -> Output; 
     _Other -> [H|Output] 
    end; 
% Count is 0 - might be unique - check with next element 
remove_unique([H1|[H2|T]],Output, 0)-> 
    case (H1 =:= H2) of 
     true -> remove_unique([H2|T],[H1|Output],1); 
     false -> remove_unique([H2|T],Output,0) 
    end; 
% Count is > 0 - not unique - proceed adding to list until next value 
remove_unique([H1|[H2|T]],Output,Count) -> 
    case (H1 =:= H2) of 
     true -> remove_unique([H2|T],[H1|Output],Count+1); 
     false -> remove_unique([H2|T],[H1|Output],0) 
    end. 

テスト

7> test:remove_unique([1,2,3,3,3,5,5,6,7,7]). 
[7,7,5,5,3,3,3] 
8> test:remove_unique([1,2,3,3,3,5,5,6,7,8]). 
[5,5,3,3,3] 
+0

ありがとうございました! –

+0

並べ替えを使わずにリストの順序を乱すことなくそれを行うにはどうしますか? –

+0

はい、同じ方法で繰り返し、要素がリストに再び表示されるかどうかを毎回確認してください。そうであれば、出力リストに追加します。それ以外の場合は追加しません。 –

4
multiple(L) -> 
    M = L -- lists:usort(L), 
    [X || X <- L , lists:member(X,M)]. 
+0

良い解決策ですが、1つの欠陥、O(n^2)の複雑さがあります。 –

+0

私は知っている、リストの典型的な長さについての指示はありませんでした、このソリューションは、私のPC上の250要素まで高速です、マップを使用してフィルタは、ますます効率的になります。 – Pascal

+0

実際、あなたのソリューションはBifsを可能な限り多く使用しているので、短いリストではかなり高速です。 –

0

は@ A.Saridの再帰/パターンマッチングの答えと同じロジックを使用して最初の質問を見たときに投稿するとき、私は書いたソリューションは、ですただし、カウントの代わりに「最後」のパラメータを使用します。

-module(only_dupes). 

-export([process/1]). 

process([]) -> []; 
process(L) when is_list(L) -> 
    [H|T] = lists:sort(L), 
    lists:sort(process(undefined, H, T, [])). 

process(Last, Curr, [], Acc) 
    when Curr =/= Last -> 
    Acc; 

process(_Last, Curr, [], Acc) -> 
    [Curr | Acc]; 

process(Last, Curr, [Next | Rest], Acc) 
    when Curr =/= Last, Curr =/= Next -> 
    process(Curr, Next, Rest, Acc); 

process(_Last, Curr, [Next | Rest], Acc) -> 
    process(Curr, Next, Rest, [Curr | Acc]). 
関連する問題