2016-09-19 73 views
2

我有以下列表項目 [{id, user1, category1}, {id, user2, category1}, {id, user1, category2}....], 其中id是唯一的,並且用戶/類別可以重複。我正試圖弄清楚如何從列表中獲取統計信息,例如erlang:元組列表中的項目

[{user1, category1, 20}, {user1, category2, 30}..]

回答

3

您可以使用列表做到這一點:與foldl/3的功能。

F = fun({_,User,Cat},Accumulator) -> 
     N = maps:get({User,Cat},Accumulator,0), 
     maps:put({User,Cat},N+1,Accumulator) end. 
CountMap = lists:foldl(F,#{},InputListe), 

這將返回地圖的形式#{{user1, category1} => 20, {user1, category2} => 30 ...}

的,如果你真的需要一個名單,那麼你必須改變地圖:

CountList = maps:fold(fun({User,Cat}, Count, Acc) -> [{User,Cat,Count}|Acc] end,[],CountMap). 

我用一箇中介地圖,因爲如果輸入列表很大,然後它可以快速訪問和快速更新,與直接在輸出列表中工作的解決方案相比較。檢索列表中的信息(平均分析列表的一半)花費很多,並且修改它也花費很多(平均複製一半列表

對於200,000個元素的輸入列表,它需要94毫秒來生成地圖並將其轉換成我的筆記本電腦上的列表,併爲219萬500000元素。

3

儘管Pascal'ssolution是一個很好的通用解決方案,對於小數據集(如高達15 000),您可以使用這個版本使用lists:sort/1,這對他們來說顯着更快。

main(L) -> 
    count(lists:sort(transform(L))). 

count([]) -> []; 
count([H|T]) -> 
    count(H, T, 1, []). 

count(H, [H|T], N, Acc) -> count(H, T, N+1, Acc); 
count({U, C}, [H|T], N, Acc) -> count(H, T, 1, [{U, C, N}|Acc]); 
count({U, C}, [], N, Acc) -> [{U, C, N}|Acc]. 

transform(L) -> 
    transform(L, []). 

transform([], Acc) -> Acc; 
transform([{_, User, Category}|T], Acc) -> 
    transform(T, [{User, Category}|Acc]). 

編輯

確定哪種算法更快的關鍵點是唯一鍵的比例。如果存在大數據集但具有少量獨特的地圖,則使用地圖的解決方案將更快。如果相反,lists:sort/1會更快。換句話說,列表與地圖的大小關係重大。

+0

:o)它提醒了我一些事情 – Pascal