我有以下列表项目 [{id, user1, category1}, {id, user2, category1}, {id, user1, category2}....],
其中id是唯一的,并且用户/类别可以重复。我正试图弄清楚如何从列表中获取统计信息,例如erlang:元组列表中的项目
[{user1, category1, 20}, {user1, category2, 30}..]
我有以下列表项目 [{id, user1, category1}, {id, user2, category1}, {id, user1, category2}....],
其中id是唯一的,并且用户/类别可以重复。我正试图弄清楚如何从列表中获取统计信息,例如erlang:元组列表中的项目
[{user1, category1, 20}, {user1, category2, 30}..]
您可以使用列表做到这一点:与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元素。
尽管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
会更快。换句话说,列表与地图的大小关系重大。
:o)它提醒了我一些事情 – Pascal