2016-08-13 79 views
3

我在erlang中包含整數值的列表。 我想刪除只發生一次的值(不重複)。刪除列表元素只出現一次

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

我是erlang的新手。我嘗試了一種方法,首先使用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

使用地圖的非常好的和簡化的解決方案。出於好奇,'map:get'的時間複雜度是多少? –

+1

@ A.Sarid:O(1)通過理論,但O(logN)在實踐中。我還沒有聽說過或看到過技術可以讓O(1)存取時間用於真正未綁定的K/V存儲器,包括存儲器或存儲器本身的線性尋址陣列,但爲什麼會這麼長時間。因此,如果您考慮真正無約束的解決方案,則此解決方案爲O(N * logN)。 –

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

不錯的解決方案,但有一個缺陷,O(n^2)的複雜性。 –

+0

我知道,沒有任何關於列表的典型長度的說明,這個解決方案在PC上可以達到250個元素,使用map的過濾器變得越來越高效。 – 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]).