2016-09-19 67 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